diff --git a/common/models/role.js b/common/models/role.js
index 87a7d24c..988d8a79 100644
--- a/common/models/role.js
+++ b/common/models/role.js
@@ -145,12 +145,10 @@ module.exports = function(Role) {
   });
 
   function isUserClass(modelClass) {
-    if (modelClass) {
-      return modelClass === loopback.User ||
-        modelClass.prototype instanceof loopback.User;
-    } else {
-      return false;
-    }
+    if (!modelClass) return false;
+    var User = modelClass.modelBuilder.models.User;
+    if (!User) return false;
+    return modelClass == User || modelClass.prototype instanceof User;
   }
 
   /*!
diff --git a/lib/builtin-models.js b/lib/builtin-models.js
index 74443333..69e986af 100644
--- a/lib/builtin-models.js
+++ b/lib/builtin-models.js
@@ -41,25 +41,6 @@ module.exports = function(registry) {
     require('../common/models/checkpoint.json'),
     require('../common/models/checkpoint.js'));
 
-  /*!
-   * Automatically attach these models to dataSources
-   */
-
-  var dataSourceTypes = {
-    DB: 'db',
-    MAIL: 'mail',
-  };
-
-  registry.Email.autoAttach = dataSourceTypes.MAIL;
-  registry.getModel('PersistedModel').autoAttach = dataSourceTypes.DB;
-  registry.User.autoAttach = dataSourceTypes.DB;
-  registry.AccessToken.autoAttach = dataSourceTypes.DB;
-  registry.Role.autoAttach = dataSourceTypes.DB;
-  registry.RoleMapping.autoAttach = dataSourceTypes.DB;
-  registry.ACL.autoAttach = dataSourceTypes.DB;
-  registry.Scope.autoAttach = dataSourceTypes.DB;
-  registry.Application.autoAttach = dataSourceTypes.DB;
-
   function createModel(definitionJson, customizeFn) {
     var Model = registry.createModel(definitionJson);
     customizeFn(Model);
diff --git a/lib/loopback.js b/lib/loopback.js
index 65ac4167..56250edb 100644
--- a/lib/loopback.js
+++ b/lib/loopback.js
@@ -363,43 +363,6 @@ loopback.createDataSource = function(name, options) {
 loopback.memory = function(name) {
   return this.registry.memory.apply(this.registry, arguments);
 };
-
-/**
- * Set the default `dataSource` for a given `type`.
- * @param {String} type The datasource type.
- * @param {Object|DataSource} dataSource The data source settings or instance
- * @returns {DataSource} The data source instance.
- *
- * @header loopback.setDefaultDataSourceForType(type, dataSource)
- */
-
-loopback.setDefaultDataSourceForType = function(type, dataSource) {
-  return this.registry.setDefaultDataSourceForType.apply(this.registry, arguments);
-};
-
-/**
- * Get the default `dataSource` for a given `type`.
- * @param {String} type The datasource type.
- * @returns {DataSource} The data source instance
- */
-
-loopback.getDefaultDataSourceForType = function(type) {
-  return this.registry.getDefaultDataSourceForType.apply(this.registry, arguments);
-};
-
-/**
- * Attach any model that does not have a dataSource to
- * the default dataSource for the type the Model requests
- */
-
-loopback.autoAttach = function() {
-  return this.registry.autoAttach.apply(this.registry, arguments);
-};
-
-loopback.autoAttachModel = function(ModelCtor) {
-  return this.registry.autoAttachModel.apply(this.registry, arguments);
-};
-
 /*!
  * Built in models / services
  */
diff --git a/lib/persisted-model.js b/lib/persisted-model.js
index 5eebf631..1ea8eaa4 100644
--- a/lib/persisted-model.js
+++ b/lib/persisted-model.js
@@ -1533,8 +1533,7 @@ module.exports = function(registry) {
       attachRelatedModels(this);
     }
 
-    // We have to attach related model whenever the datasource changes,
-    // this is a workaround for autoAttach called by loopback.createModel
+    // Re-attach related models whenever our datasource is changed.
     var self = this;
     this.on('dataSourceAttached', function() {
       attachRelatedModels(self);
diff --git a/lib/registry.js b/lib/registry.js
index 35d247e2..fad30f10 100644
--- a/lib/registry.js
+++ b/lib/registry.js
@@ -118,11 +118,6 @@ Registry.prototype.createModel = function(name, properties, options) {
 
   this._defineRemoteMethods(model, options.methods);
 
-  // try to attach
-  try {
-    this.autoAttachModel(model);
-  } catch (e) {}
-
   return model;
 };
 
@@ -368,7 +363,8 @@ Registry.prototype.createDataSource = function(name, options) {
   };
 
   if (ds.settings && ds.settings.defaultForType) {
-    this.setDefaultDataSourceForType(ds.settings.defaultForType, ds);
+    var msg = 'DataSource option "defaultForType" is no longer supported';
+    throw new Error(msg);
   }
 
   return ds;
@@ -395,66 +391,3 @@ Registry.prototype.memory = function(name) {
 
   return memory;
 };
-
-/**
- * Set the default `dataSource` for a given `type`.
- * @param {String} type The datasource type.
- * @param {Object|DataSource} dataSource The data source settings or instance
- * @returns {DataSource} The data source instance.
- *
- * @header loopback.setDefaultDataSourceForType(type, dataSource)
- */
-
-Registry.prototype.setDefaultDataSourceForType = function(type, dataSource) {
-  var defaultDataSources = this.defaultDataSources;
-
-  if (!(dataSource instanceof DataSource)) {
-    dataSource = this.createDataSource(dataSource);
-  }
-
-  defaultDataSources[type] = dataSource;
-  return dataSource;
-};
-
-/**
- * Get the default `dataSource` for a given `type`.
- * @param {String} type The datasource type.
- * @returns {DataSource} The data source instance
- */
-
-Registry.prototype.getDefaultDataSourceForType = function(type) {
-  return this.defaultDataSources && this.defaultDataSources[type];
-};
-
-/**
- * Attach any model that does not have a dataSource to
- * the default dataSource for the type the Model requests
- */
-
-Registry.prototype.autoAttach = function() {
-  var models = this.modelBuilder.models;
-  assert.equal(typeof models, 'object', 'Cannot autoAttach without a models object');
-
-  Object.keys(models).forEach(function(modelName) {
-    var ModelCtor = models[modelName];
-
-    // Only auto attach if the model doesn't have an explicit data source
-    if (ModelCtor && (!(ModelCtor.dataSource instanceof DataSource))) {
-      this.autoAttachModel(ModelCtor);
-    }
-  }, this);
-};
-
-Registry.prototype.autoAttachModel = function(ModelCtor) {
-  if (ModelCtor.autoAttach) {
-    var ds = this.getDefaultDataSourceForType(ModelCtor.autoAttach);
-
-    assert(
-      ds instanceof DataSource,
-      'cannot autoAttach model "' + ModelCtor.modelName +
-      '". No dataSource found of type ' + ModelCtor.autoAttach
-    );
-
-    ModelCtor.attachTo(ds);
-  }
-};
diff --git a/package.json b/package.json
index 43c4dbd0..98be9798 100644
--- a/package.json
+++ b/package.json
@@ -102,5 +102,10 @@
     "depd": "loopback-datasource-juggler/lib/browser.depd.js",
     "bcrypt": false
   },
+  "config": {
+    "ci": {
+      "debug": "*,-mocha:*,-eslint:*"
+    }
+  },
   "license": "MIT"
 }
diff --git a/test/email.test.js b/test/email.test.js
index 49cf189d..04089dee 100644
--- a/test/email.test.js
+++ b/test/email.test.js
@@ -37,7 +37,11 @@ describe('Email connector', function() {
 describe('Email and SMTP', function() {
   beforeEach(function() {
     MyEmail = loopback.Email.extend('my-email');
-    loopback.autoAttach();
+    var ds = loopback.createDataSource('email', {
+      connector: loopback.Mail,
+      transports: [{ type: 'STUB' }],
+    });
+    MyEmail.attachTo(ds);
   });
 
   it('should have a send method', function() {
diff --git a/test/integration.test.js b/test/integration.test.js
index f88ed1b7..2cceb01d 100644
--- a/test/integration.test.js
+++ b/test/integration.test.js
@@ -24,7 +24,6 @@ describe('loopback application', function() {
     function setupAppWithStreamingMethod() {
       app.dataSource('db', {
         connector: loopback.Memory,
-        defaultForType: 'db',
       });
       var db = app.datasources.db;
 
diff --git a/test/loopback.test.js b/test/loopback.test.js
index a9240615..801531fb 100644
--- a/test/loopback.test.js
+++ b/test/loopback.test.js
@@ -53,8 +53,6 @@ describe('loopback', function() {
         'ValidationError',
         'application',
         'arguments',
-        'autoAttach',
-        'autoAttachModel',
         'bodyParser',
         'caller',
         'compress',
@@ -73,7 +71,6 @@ describe('loopback', function() {
         'faviconFile',
         'findModel',
         'getCurrentContext',
-        'getDefaultDataSourceForType',
         'getModel',
         'getModelByType',
         'isBrowser',
@@ -96,7 +93,6 @@ describe('loopback', function() {
         'rest',
         'runInContext',
         'session',
-        'setDefaultDataSourceForType',
         'static',
         'status',
         'template',
@@ -158,32 +154,6 @@ describe('loopback', function() {
     });
   });
 
-  describe('loopback.autoAttach', function() {
-    it('doesn\'t overwrite model with datasource configured', function() {
-      var ds1 = loopback.createDataSource('db1', {
-        connector: loopback.Memory,
-      });
-
-      // setup default data sources
-      loopback.setDefaultDataSourceForType('db', ds1);
-
-      var ds2 = loopback.createDataSource('db2', {
-        connector: loopback.Memory,
-      });
-
-      var model1 = ds2.createModel('m1', {});
-
-      var model2 = loopback.createModel('m2');
-      model2.autoAttach = 'db';
-
-      // auto attach data sources to models
-      loopback.autoAttach();
-
-      assert(model1.dataSource === ds2);
-      assert(model2.dataSource === ds1);
-    });
-  });
-
   describe('loopback.remoteMethod(Model, fn, [options]);', function() {
     it('Setup a remote method.', function() {
       var Product = loopback.createModel('product', { price: Number });
@@ -370,6 +340,14 @@ describe('loopback', function() {
       var db = loopback.createDataSource({ connector: loopback.Memory });
       var model = loopback.Model.extend(uniqueModelName);
 
+      // This test used to work because User model was already attached
+      // by other tests via `loopback.autoAttach()`
+      // Now that autoAttach is gone, it turns out the tested functionality
+      // does not work exactly as intended. To keep this change narrowly
+      // focused on removing autoAttach, we are attaching the User model
+      // to simulate the old test setup.
+      loopback.User.attachTo(db);
+
       loopback.configureModel(model, {
         dataSource: db,
         relations: {
diff --git a/test/model.application.test.js b/test/model.application.test.js
index b3ac7634..ed606b2a 100644
--- a/test/model.application.test.js
+++ b/test/model.application.test.js
@@ -5,6 +5,10 @@ var Application = loopback.Application;
 describe('Application', function() {
   var registeredApp = null;
 
+  before(function attachToMemory() {
+    Application.attachTo(loopback.memory());
+  });
+
   it('honors `application.register` - promise variant', function(done) {
     Application.register('rfeng', 'MyTestApp',
       { description: 'My test application' }, function(err, result) {
diff --git a/test/rest.middleware.test.js b/test/rest.middleware.test.js
index d1a98a4b..3de92301 100644
--- a/test/rest.middleware.test.js
+++ b/test/rest.middleware.test.js
@@ -1,11 +1,15 @@
 var path = require('path');
 
 describe('loopback.rest', function() {
-  var MyModel;
+  var app, MyModel;
+
   beforeEach(function() {
-    var ds = app.dataSource('db', { connector: loopback.Memory });
-    MyModel = ds.createModel('MyModel', { name: String });
-    loopback.autoAttach();
+    // override the global app object provided by test/support.js
+    // and create a local one that does not share state with other tests
+    app = loopback({ localRegistry: true, loadBuiltinModels: true });
+    var db = app.dataSource('db', { connector: 'memory' });
+    MyModel = app.registry.createModel('MyModel');
+    MyModel.attachTo(db);
   });
 
   it('works out-of-the-box', function(done) {
@@ -101,7 +105,7 @@ describe('loopback.rest', function() {
   });
 
   it('should honour `remoting.rest.supportedTypes`', function(done) {
-    var app = loopback();
+    var app = loopback({ localRegistry: true });
 
     // NOTE it is crucial to set `remoting` before creating any models
     var supportedTypes = ['json', 'application/javascript', 'text/javascript'];
@@ -117,26 +121,24 @@ describe('loopback.rest', function() {
   });
 
   it('allows models to provide a custom HTTP path', function(done) {
-    var ds = app.dataSource('db', { connector: loopback.Memory });
-    var CustomModel = ds.createModel('CustomModel',
+    var CustomModel = app.registry.createModel('CustomModel',
       { name: String },
       { http: { 'path': 'domain1/CustomModelPath' },
     });
 
-    app.model(CustomModel);
+    app.model(CustomModel, { dataSource: 'db' });
     app.use(loopback.rest());
 
     request(app).get('/domain1/CustomModelPath').expect(200).end(done);
   });
 
   it('should report 200 for url-encoded HTTP path', function(done) {
-    var ds = app.dataSource('db', { connector: loopback.Memory });
-    var CustomModel = ds.createModel('CustomModel',
+    var CustomModel = app.registry.createModel('CustomModel',
       { name: String },
       { http: { path: 'domain%20one/CustomModelPath' },
     });
 
-    app.model(CustomModel);
+    app.model(CustomModel, { dataSource: 'db' });
     app.use(loopback.rest());
 
     request(app).get('/domain%20one/CustomModelPath').expect(200).end(done);
@@ -144,12 +146,12 @@ describe('loopback.rest', function() {
 
   it('includes loopback.token when necessary', function(done) {
     givenUserModelWithAuth();
-    app.enableAuth();
+    app.enableAuth({ dataSource: 'db' });
     app.use(loopback.rest());
 
     givenLoggedInUser(function(err, token) {
       if (err) return done(err);
-      expect(token).instanceOf(app.models.accessToken);
+      expect(token).instanceOf(app.models.AccessToken);
       request(app).get('/users/' + token.userId)
         .set('Authorization', token.id)
         .expect(200)
@@ -268,14 +270,14 @@ describe('loopback.rest', function() {
 
     it('should enable context using loopback.context', function(done) {
       app.use(loopback.context({ enableHttpContext: true }));
-      app.enableAuth();
+      app.enableAuth({ dataSource: 'db' });
       app.use(loopback.rest());
 
       invokeGetToken(done);
     });
 
     it('should enable context with loopback.rest', function(done) {
-      app.enableAuth();
+      app.enableAuth({ dataSource: 'db' });
       app.set('remoting', { context: { enableHttpContext: true }});
       app.use(loopback.rest());
 
@@ -283,10 +285,10 @@ describe('loopback.rest', function() {
     });
 
     it('should support explicit context', function(done) {
-      app.enableAuth();
+      app.enableAuth({ dataSource: 'db' });
       app.use(loopback.context());
       app.use(loopback.token(
-        { model: loopback.getModelByType(loopback.AccessToken) }));
+        { model: app.registry.getModelByType('AccessToken') }));
       app.use(function(req, res, next) {
         loopback.getCurrentContext().set('accessToken', req.accessToken);
         next();
@@ -321,32 +323,26 @@ describe('loopback.rest', function() {
   });
 
   function givenUserModelWithAuth() {
-    // NOTE(bajtos) It is important to create a custom AccessToken model here,
-    // in order to overwrite the entry created by previous tests in
-    // the global model registry
-    app.model('accessToken', {
-      options: {
-        base: 'AccessToken',
-      },
-      dataSource: 'db',
-    });
-    return app.model('user', {
-      options: {
-        base: 'User',
-        relations: {
-          accessTokens: {
-            model: 'accessToken',
-            type: 'hasMany',
-            foreignKey: 'userId',
-          },
-        },
-      },
-      dataSource: 'db',
-    });
+    var AccessToken = app.registry.getModel('AccessToken');
+    app.model(AccessToken, { dataSource: 'db' });
+    var User = app.registry.getModel('User');
+    app.model(User, { dataSource: 'db' });
+
+    // NOTE(bajtos) This is puzzling to me. The built-in User & AccessToken
+    // models should come with both relations already set up, i.e. the
+    // following two lines should not be neccessary.
+    // And it does behave that way when only tests in this file are run.
+    // However, when I run the full test suite (all files), the relations
+    // get broken.
+    AccessToken.belongsTo(User, { as: 'user', foreignKey: 'userId' });
+    User.hasMany(AccessToken, { as: 'accessTokens', foreignKey: 'userId' });
+
+    return User;
   }
+
   function givenLoggedInUser(cb, done) {
     var credentials = { email: 'user@example.com', password: 'pwd' };
-    var User = app.models.user;
+    var User = app.models.User;
     User.create(credentials,
       function(err, user) {
         if (err) return done(err);
diff --git a/test/role.test.js b/test/role.test.js
index 8ecddde2..36a18af5 100644
--- a/test/role.test.js
+++ b/test/role.test.js
@@ -434,4 +434,28 @@ describe('role model', function() {
       });
     });
   });
+
+  describe('isOwner', function() {
+    it('supports app-local model registry', function(done) {
+      var app = loopback({ localRegistry: true, loadBuiltinModels: true });
+      app.dataSource('db', { connector: 'memory' });
+      // attach all auth-related models to 'db' datasource
+      app.enableAuth({ dataSource: 'db' });
+
+      var Role = app.models.Role;
+      var User = app.models.User;
+
+      var u = app.registry.findModel('User');
+      var credentials = { email: 'test@example.com', password: 'pass' };
+      User.create(credentials, function(err, user) {
+        if (err) return done(err);
+
+        Role.isOwner(User, user.id, user.id, function(err, result) {
+          if (err) return done(err);
+          expect(result, 'isOwner result').to.equal(true);
+          done();
+        });
+      });
+    });
+  });
 });
diff --git a/test/support.js b/test/support.js
index b3fef0b3..d7f4f0c1 100644
--- a/test/support.js
+++ b/test/support.js
@@ -18,18 +18,6 @@ loopback.User.settings.saltWorkFactor = 4;
 
 beforeEach(function() {
   this.app = app = loopback();
-
-  // setup default data sources
-  loopback.setDefaultDataSourceForType('db', {
-    connector: loopback.Memory,
-  });
-
-  loopback.setDefaultDataSourceForType('mail', {
-    connector: loopback.Mail,
-    transports: [
-      { type: 'STUB' },
-    ],
-  });
 });
 
 assertValidDataSource = function(dataSource) {
diff --git a/test/user.test.js b/test/user.test.js
index 75fd67d7..adbc6ea7 100644
--- a/test/user.test.js
+++ b/test/user.test.js
@@ -1,11 +1,6 @@
 require('./support');
 var loopback = require('../');
 var User, AccessToken;
-var MailConnector = require('../lib/connectors/mail');
-
-var userMemory = loopback.createDataSource({
-  connector: 'memory',
-});
 
 describe('User', function() {
   var validCredentialsEmail = 'foo@bar.com';
@@ -21,44 +16,59 @@ describe('User', function() {
   var invalidCredentials = { email: 'foo1@bar.com', password: 'invalid' };
   var incompleteCredentials = { password: 'bar1' };
 
-  var defaultApp;
+  // Create a local app variable to prevent clashes with the global
+  // variable shared by all tests. While this should not be necessary if
+  // the tests were written correctly, it turns out that's not the case :(
+  var app;
 
-  beforeEach(function() {
-    // FIXME: [rfeng] Remove loopback.User.app so that remote hooks don't go
-    // to the wrong app instance
-    defaultApp = loopback.User.app;
-    loopback.User.app = null;
-    User = loopback.User.extend('TestUser', {}, { http: { path: 'test-users' }});
-    AccessToken = loopback.AccessToken.extend('TestAccessToken');
-    User.email = loopback.Email.extend('email');
-    loopback.autoAttach();
+  beforeEach(function setupAppAndModels(done) {
+    // override the global app object provided by test/support.js
+    // and create a local one that does not share state with other tests
+    app = loopback({ localRegistry: true, loadBuiltinModels: true });
+    app.dataSource('db', { connector: 'memory' });
+
+    // setup Email model, it's needed by User tests
+    app.dataSource('email', {
+      connector: loopback.Mail,
+      transports: [{ type: 'STUB' }],
+    });
+    var Email = app.registry.getModel('Email');
+    app.model(Email, { dataSource: 'email' });
+
+    // attach User and related models
+    User = app.registry.createModel('TestUser', {}, {
+      base: 'User',
+      http: { path: 'test-users' },
+    });
+    app.model(User, { dataSource: 'db' });
+
+    AccessToken = app.registry.getModel('AccessToken');
+    app.model(AccessToken, { dataSource: 'db' });
+
+    User.email = Email;
 
     // Update the AccessToken relation to use the subclass of User
     AccessToken.belongsTo(User, { as: 'user', foreignKey: 'userId' });
     User.hasMany(AccessToken, { as: 'accessTokens', foreignKey: 'userId' });
 
+    // Speed up the password hashing algorithm
+    // for tests using the built-in User model
+    User.settings.saltWorkFactor = 4;
+
     // allow many User.afterRemote's to be called
     User.setMaxListeners(0);
-  });
 
-  beforeEach(function(done) {
-    app.enableAuth();
+    app.enableAuth({ dataSource: 'db' });
     app.use(loopback.token({ model: AccessToken }));
     app.use(loopback.rest());
     app.model(User);
 
     User.create(validCredentials, function(err, user) {
+      if (err) return done(err);
       User.create(validCredentialsEmailVerified, done);
     });
   });
 
-  afterEach(function(done) {
-    loopback.User.app = defaultApp;
-    User.destroyAll(function(err) {
-      User.accessToken.destroyAll(done);
-    });
-  });
-
   describe('User.create', function() {
     it('Create a new user', function(done) {
       User.create({ email: 'f@b.com', password: 'bar' }, function(err, user) {
@@ -700,12 +710,19 @@ describe('User', function() {
   describe('User.login requiring realm', function() {
     var User, AccessToken;
 
-    before(function() {
-      User = loopback.User.extend('RealmUser', {},
-        { realmRequired: true, realmDelimiter: ':' });
-      AccessToken = loopback.AccessToken.extend('RealmAccessToken');
+    beforeEach(function() {
+      User = app.registry.createModel('RealmUser', {}, {
+        base: 'TestUser',
+        realmRequired: true,
+        realmDelimiter: ':',
+      });
 
-      loopback.autoAttach();
+      AccessToken = app.registry.createModel('RealmAccessToken', {}, {
+        base: 'AccessToken',
+      });
+
+      app.model(AccessToken, { dataSource: 'db' });
+      app.model(User, { dataSource: 'db' });
 
       // Update the AccessToken relation to use the subclass of User
       AccessToken.belongsTo(User, { as: 'user', foreignKey: 'userId' });
@@ -776,15 +793,6 @@ describe('User', function() {
       });
     });
 
-    afterEach(function(done) {
-      User.deleteAll({ realm: 'realm1' }, function(err) {
-        if (err) {
-          return done(err);
-        }
-        User.deleteAll({ realm: 'realm2' }, done);
-      });
-    });
-
     it('rejects a user by without realm', function(done) {
       User.login(credentialWithoutRealm, function(err, accessToken) {
         assert(err);
@@ -834,11 +842,11 @@ describe('User', function() {
     });
 
     describe('User.login with realmRequired but no realmDelimiter', function() {
-      before(function() {
+      beforeEach(function() {
         User.settings.realmDelimiter = undefined;
       });
 
-      after(function() {
+      afterEach(function() {
         User.settings.realmDelimiter = ':';
       });
 
@@ -1544,7 +1552,7 @@ describe('User', function() {
   describe('ctor', function() {
     it('exports default Email model', function() {
       expect(User.email, 'User.email').to.be.a('function');
-      expect(User.email.modelName, 'modelName').to.eql('email');
+      expect(User.email.modelName, 'modelName').to.eql('Email');
     });
 
     it('exports default AccessToken model', function() {