diff --git a/includes/common.inc b/includes/common.inc
index 1e287f8..b67ede9 100644
--- a/includes/common.inc
+++ b/includes/common.inc
@@ -7128,7 +7128,11 @@ function drupal_flush_all_caches() {
   system_rebuild_theme_data();
   drupal_theme_rebuild();
 
-  node_types_rebuild();
+  // @todo D8: Split cache flushing from rebuilding.
+  // @see http://drupal.org/node/996236
+  if (module_exists('node')) {
+    node_types_rebuild();
+  }
   // node_menu() defines menu items based on node types so it needs to come
   // after node types are rebuilt.
   menu_rebuild();
diff --git a/includes/module.inc b/includes/module.inc
index 66c77f5..3349f67 100644
--- a/includes/module.inc
+++ b/includes/module.inc
@@ -517,11 +517,6 @@ function module_disable($module_list, $disable_dependents = TRUE) {
 
   foreach ($module_list as $module) {
     if (module_exists($module)) {
-      // Check if node_access table needs rebuilding.
-      if (!node_access_needs_rebuild() && module_hook($module, 'node_grants')) {
-        node_access_needs_rebuild(TRUE);
-      }
-
       module_load_install($module);
       module_invoke($module, 'disable');
       db_update('system')
@@ -546,12 +541,6 @@ function module_disable($module_list, $disable_dependents = TRUE) {
     registry_update();
     _system_update_bootstrap_status();
   }
-
-  // If there remains no more node_access module, rebuilding will be
-  // straightforward, we can do it right now.
-  if (node_access_needs_rebuild() && count(module_implements('node_grants')) == 0) {
-    node_access_rebuild();
-  }
 }
 
 /**
diff --git a/includes/path.inc b/includes/path.inc
index db60537..7b2ea9a 100644
--- a/includes/path.inc
+++ b/includes/path.inc
@@ -17,7 +17,7 @@ function drupal_path_initialize() {
     $_GET['q'] = drupal_get_normal_path($_GET['q']);
   }
   else {
-    $_GET['q'] = drupal_get_normal_path(variable_get('site_frontpage', 'node'));
+    $_GET['q'] = drupal_get_normal_path(variable_get('site_frontpage', 'user'));
   }
 }
 
@@ -292,7 +292,7 @@ function drupal_is_front_page() {
   if (!isset($is_front_page)) {
     // As drupal_path_initialize updates $_GET['q'] with the 'site_frontpage' path,
     // we can check it against the 'site_frontpage' variable.
-    $is_front_page = ($_GET['q'] == variable_get('site_frontpage', 'node'));
+    $is_front_page = ($_GET['q'] == variable_get('site_frontpage', 'user'));
   }
 
   return $is_front_page;
@@ -323,7 +323,7 @@ function drupal_match_path($path, $patterns) {
     $replacements = array(
       '|',
       '.*',
-      '\1' . preg_quote(variable_get('site_frontpage', 'node'), '/') . '\2'
+      '\1' . preg_quote(variable_get('site_frontpage', 'user'), '/') . '\2'
     );
     $patterns_quoted = preg_quote($patterns, '/');
     $regexps[$patterns] = '/^(' . preg_replace($to_replace, $replacements, $patterns_quoted) . ')$/';
diff --git a/modules/blog/blog.info b/modules/blog/blog.info
index b962d28..944794f 100644
--- a/modules/blog/blog.info
+++ b/modules/blog/blog.info
@@ -3,4 +3,5 @@ description = Enables multi-user blogs.
 package = Core
 version = VERSION
 core = 8.x
+dependencies[] = node
 files[] = blog.test
diff --git a/modules/book/book.info b/modules/book/book.info
index 0f4d2b1..114b212 100644
--- a/modules/book/book.info
+++ b/modules/book/book.info
@@ -3,6 +3,7 @@ description = Allows users to create and organize related content in an outline.
 package = Core
 version = VERSION
 core = 8.x
+dependencies[] = node
 files[] = book.test
 configure = admin/content/book/settings
 stylesheets[all][] = book.css
diff --git a/modules/comment/comment.info b/modules/comment/comment.info
index a5837af..19940e2 100644
--- a/modules/comment/comment.info
+++ b/modules/comment/comment.info
@@ -3,6 +3,7 @@ description = Allows users to comment on and discuss published content.
 package = Core
 version = VERSION
 core = 8.x
+dependencies[] = node
 dependencies[] = text
 files[] = comment.module
 files[] = comment.test
diff --git a/modules/forum/forum.info b/modules/forum/forum.info
index cb6e3e7..f202f9e 100644
--- a/modules/forum/forum.info
+++ b/modules/forum/forum.info
@@ -1,5 +1,6 @@
 name = Forum
 description = Provides discussion forums.
+dependencies[] = node
 dependencies[] = taxonomy
 dependencies[] = comment
 package = Core
diff --git a/modules/locale/locale.install b/modules/locale/locale.install
index 7fbc81d..5044f9a 100644
--- a/modules/locale/locale.install
+++ b/modules/locale/locale.install
@@ -65,9 +65,11 @@ function locale_uninstall() {
     variable_del("locale_language_providers_weight_$type");
   }
 
-  foreach (node_type_get_types() as $type => $content_type) {
-    $setting = variable_del("language_content_type_$type");
-  }
+  // Remove all node type language variables. Node module might have been
+  // enabled, but may be disabled, so use a wildcard delete.
+  db_delete('variable')
+    ->condition('name', 'language_content_type_%', 'LIKE')
+    ->execute();
 
   // Switch back to English: with a $language->language value different from 'en'
   // successive calls of t() might result in calling locale(), which in turn might
diff --git a/modules/node/node.info b/modules/node/node.info
index 7f2c7ff..0b2b765 100644
--- a/modules/node/node.info
+++ b/modules/node/node.info
@@ -5,6 +5,5 @@ version = VERSION
 core = 8.x
 files[] = node.module
 files[] = node.test
-required = TRUE
 configure = admin/structure/types
 stylesheets[all][] = node.css
diff --git a/modules/node/node.module b/modules/node/node.module
index 1ecc093..a18a58a 100644
--- a/modules/node/node.module
+++ b/modules/node/node.module
@@ -3898,6 +3898,28 @@ function node_modules_enabled($modules) {
 }
 
 /**
+ * Implements hook_modules_disabled().
+ */
+function node_modules_disabled($modules) {
+  // Check whether any of the disabled modules implemented hook_node_grants(),
+  // in which case the node access table needs to be rebuilt.
+  foreach ($modules as $module) {
+    // At this point, the module is already disabled, but its code is still
+    // loaded in memory. Module functions must no longer be called. We only
+    // check whether a hook implementation function exists and do not invoke it.
+    if (!node_access_needs_rebuild() && module_hook($module, 'node_grants')) {
+      node_access_needs_rebuild(TRUE);
+    }
+  }
+
+  // If there remains no more node_access module, rebuilding will be
+  // straightforward, we can do it right now.
+  if (node_access_needs_rebuild() && count(module_implements('node_grants')) == 0) {
+    node_access_rebuild();
+  }
+}
+
+/**
  * Controller class for nodes.
  *
  * This extends the DrupalDefaultEntityController class, adding required
diff --git a/modules/overlay/overlay.module b/modules/overlay/overlay.module
index 9af18e1..900e307 100644
--- a/modules/overlay/overlay.module
+++ b/modules/overlay/overlay.module
@@ -638,7 +638,7 @@ function overlay_overlay_parent_initialize() {
   // Let the client side know which paths are administrative.
   $paths = path_get_admin_paths();
   foreach ($paths as &$type) {
-    $type = str_replace('<front>', variable_get('site_frontpage', 'node'), $type);
+    $type = str_replace('<front>', variable_get('site_frontpage', 'user'), $type);
   }
   drupal_add_js(array('overlay' => array('paths' => $paths)), 'setting');
   // Pass along the Ajax callback for rerendering sections of the parent window.
diff --git a/modules/poll/poll.info b/modules/poll/poll.info
index de6ac25..dbdd621 100644
--- a/modules/poll/poll.info
+++ b/modules/poll/poll.info
@@ -3,5 +3,6 @@ description = Allows your site to capture votes on different topics in the form
 package = Core
 version = VERSION
 core = 8.x
+dependencies[] = node
 files[] = poll.test
 stylesheets[all][] = poll.css
diff --git a/modules/rdf/tests/rdf_test.info b/modules/rdf/tests/rdf_test.info
index b168815..a65cc59 100644
--- a/modules/rdf/tests/rdf_test.info
+++ b/modules/rdf/tests/rdf_test.info
@@ -4,3 +4,8 @@ package = Testing
 version = VERSION
 core = 8.x
 hidden = TRUE
+; module_enable() sorts modules with dependencies _always_ after modules without
+; dependencies. Blog module depends on Node module, so it is sorted last.
+; rdf_test module attempts to override Blog module's RDF mapping, so a
+; dependency is needed to sort it into "groups of modules having dependencies".
+dependencies[] = rdf
diff --git a/modules/shortcut/shortcut.install b/modules/shortcut/shortcut.install
index 60ee6be..7aee9c9 100644
--- a/modules/shortcut/shortcut.install
+++ b/modules/shortcut/shortcut.install
@@ -13,18 +13,19 @@ function shortcut_install() {
   // Create an initial default shortcut set.
   $shortcut_set = new stdClass();
   $shortcut_set->title = $t('Default');
-  $shortcut_set->links = array(
-    array(
+  $shortcut_set->links = array();
+  if (module_exists('node')) {
+    $shortcut_set->links[] = array(
       'link_path' => 'node/add',
       'link_title' => $t('Add content'),
       'weight' => -20,
-    ),
-    array(
+    );
+    $shortcut_set->links[] = array(
       'link_path' => 'admin/content',
       'link_title' => $t('Find content'),
       'weight' => -19,
-    ),
-  );
+    );
+  }
   // If Drupal is being installed, rebuild the menu before saving the shortcut
   // set, to make sure the links defined above can be correctly saved. (During
   // installation, the menu might not have been built at all yet, or it might
diff --git a/modules/simpletest/drupal_web_test_case.php b/modules/simpletest/drupal_web_test_case.php
index 5c39cfc..b9167b3 100644
--- a/modules/simpletest/drupal_web_test_case.php
+++ b/modules/simpletest/drupal_web_test_case.php
@@ -1045,26 +1045,33 @@ class DrupalWebTestCase extends DrupalTestCase {
   }
 
   /**
-   * Create a user with a given set of permissions. The permissions correspond to the
-   * names given on the privileges page.
+   * Create a user with a given set of permissions.
    *
    * @param $permissions
-   *   Array of permission names to assign to user.
+   *   Array of permission names to assign to user. Note that the user always
+   *   has the default permissions derived from the "authenticated users" role.
+   *
    * @return
    *   A fully loaded user object with pass_raw property, or FALSE if account
    *   creation fails.
    */
-  protected function drupalCreateUser($permissions = array('access comments', 'access content', 'post comments', 'skip comment approval')) {
-    // Create a role with the given permission set.
-    if (!($rid = $this->drupalCreateRole($permissions))) {
-      return FALSE;
+  protected function drupalCreateUser(array $permissions = array()) {
+    // Create a role with the given permissions, if any.
+    $rid = FALSE;
+    if ($permissions) {
+      $rid = $this->drupalCreateRole($permissions);
+      if (!$rid) {
+        return FALSE;
+      }
     }
 
     // Create a user assigned to that role.
     $edit = array();
     $edit['name']   = $this->randomName();
     $edit['mail']   = $edit['name'] . '@example.com';
-    $edit['roles']  = array($rid => $rid);
+    if ($rid) {
+      $edit['roles']  = array($rid => $rid);
+    }
     $edit['pass']   = user_password();
     $edit['status'] = 1;
 
diff --git a/modules/simpletest/tests/database_test.test b/modules/simpletest/tests/database_test.test
index e27693c..f9d6e33 100644
--- a/modules/simpletest/tests/database_test.test
+++ b/modules/simpletest/tests/database_test.test
@@ -19,7 +19,12 @@ class DatabaseTestCase extends DrupalWebTestCase {
   protected $profile = 'testing';
 
   function setUp() {
-    parent::setUp('database_test');
+    $modules = func_get_args();
+    if (isset($modules[0]) && is_array($modules[0])) {
+      $modules = $modules[0];
+    }
+    $modules[] = 'database_test';
+    parent::setUp($modules);
 
     $schema['test'] = drupal_get_schema('test');
     $schema['test_people'] = drupal_get_schema('test_people');
@@ -377,10 +382,6 @@ class DatabaseFetch2TestCase extends DatabaseTestCase {
     );
   }
 
-  function setUp() {
-    parent::setUp();
-  }
-
   // Confirm that we can fetch a record into an indexed array explicitly.
   function testQueryFetchNum() {
     $records = array();
@@ -2188,24 +2189,14 @@ class DatabaseSelectComplexTestCase2 extends DatabaseTestCase {
   }
 
   function setUp() {
-    DrupalWebTestCase::setUp('database_test', 'node_access_test');
-
-    $schema['test'] = drupal_get_schema('test');
-    $schema['test_people'] = drupal_get_schema('test_people');
-    $schema['test_one_blob'] = drupal_get_schema('test_one_blob');
-    $schema['test_two_blobs'] = drupal_get_schema('test_two_blobs');
-    $schema['test_task'] = drupal_get_schema('test_task');
-
-    $this->installTables($schema);
-
-    $this->addSampleData();
+    parent::setUp(array('node_access_test'));
   }
 
   /**
    * Test that we can join on a query.
    */
   function testJoinSubquery() {
-    $acct = $this->drupalCreateUser(array('access content'));
+    $acct = $this->drupalCreateUser();
     $this->drupalLogin($acct);
 
     $query = db_select('test_task', 'tt', array('target' => 'slave'));
@@ -2724,6 +2715,10 @@ class DatabaseRegressionTestCase extends DatabaseTestCase {
     );
   }
 
+  function setUp() {
+    parent::setUp(array('node'));
+  }
+
   /**
    * Regression test for #310447.
    *
@@ -3015,10 +3010,6 @@ class DatabaseBasicSyntaxTestCase extends DatabaseTestCase {
     );
   }
 
-  function setUp() {
-    parent::setUp('database_test');
-  }
-
   /**
    * Test for string concatenation.
    */
@@ -3116,10 +3107,6 @@ class DatabaseInvalidDataTestCase extends DatabaseTestCase {
     );
   }
 
-  function setUp() {
-    parent::setUp('database_test');
-  }
-
   /**
    * Traditional SQL database systems abort inserts when invalid data is encountered.
    */
@@ -3189,10 +3176,6 @@ class DatabaseQueryTestCase extends DatabaseTestCase {
     );
   }
 
-  function setUp() {
-    parent::setUp('database_test');
-  }
-
   /**
    * Test that we can specify an array of values in the query by simply passing in an array.
    */
diff --git a/modules/system/system.admin.inc b/modules/system/system.admin.inc
index 3313f5a..4779711 100644
--- a/modules/system/system.admin.inc
+++ b/modules/system/system.admin.inc
@@ -1484,7 +1484,7 @@ function system_site_information_settings() {
   $form['front_page']['site_frontpage'] = array(
     '#type' => 'textfield',
     '#title' => t('Default front page'),
-    '#default_value' => (variable_get('site_frontpage')!='node'?drupal_get_path_alias(variable_get('site_frontpage', 'node')):''),
+    '#default_value' => (variable_get('site_frontpage') != 'user' ? drupal_get_path_alias(variable_get('site_frontpage', 'user')) : ''),
     '#size' => 40,
     '#description' => t('Optionally, specify a relative URL to display as the front page.  Leave blank to display the default content feed.'),
     '#field_prefix' => url(NULL, array('absolute' => TRUE)) . (variable_get('clean_url', 0) ? '' : '?q='),
@@ -1525,8 +1525,8 @@ function system_site_information_settings_validate($form, &$form_state) {
   }
   // Check for empty front page path.
   if (empty($form_state['values']['site_frontpage'])) {
-    // Set to default "node".
-    form_set_value($form['front_page']['site_frontpage'], 'node', $form_state);
+    // Set to default "user".
+    form_set_value($form['front_page']['site_frontpage'], 'user', $form_state);
   }
   else {
     // Get the normal path of the front page.
diff --git a/profiles/minimal/minimal.info b/profiles/minimal/minimal.info
index c384680..f221948 100644
--- a/profiles/minimal/minimal.info
+++ b/profiles/minimal/minimal.info
@@ -2,6 +2,7 @@ name = Minimal
 description = Start with only a few modules enabled.
 version = VERSION
 core = 8.x
+dependencies[] = node
 dependencies[] = block
 dependencies[] = dblog
 files[] = minimal.profile
diff --git a/profiles/minimal/minimal.install b/profiles/minimal/minimal.install
index 059f038..d29b9ad 100644
--- a/profiles/minimal/minimal.install
+++ b/profiles/minimal/minimal.install
@@ -66,6 +66,9 @@ function minimal_install() {
   }
   $query->execute();
 
+  // Set front page to "node".
+  variable_set('site_frontpage', 'node');
+
   // Allow visitor account creation, but with administrative approval.
   variable_set('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL);
 
diff --git a/profiles/standard/standard.info b/profiles/standard/standard.info
index 56e4308..e21c18c 100644
--- a/profiles/standard/standard.info
+++ b/profiles/standard/standard.info
@@ -2,6 +2,7 @@ name = Standard
 description = Install with commonly used features pre-configured.
 version = VERSION
 core = 8.x
+dependencies[] = node
 dependencies[] = block
 dependencies[] = color
 dependencies[] = comment
diff --git a/profiles/standard/standard.install b/profiles/standard/standard.install
index 5d44717..fa5383c 100644
--- a/profiles/standard/standard.install
+++ b/profiles/standard/standard.install
@@ -193,6 +193,9 @@ function standard_install() {
   }
   $query->execute();
 
+  // Set front page to "node".
+  variable_set('site_frontpage', 'node');
+
   // Insert default pre-defined node types into the database. For a complete
   // list of available node type attributes, refer to the node type API
   // documentation at: http://api.drupal.org/api/HEAD/function/hook_node_info.
diff --git a/profiles/testing/testing.install b/profiles/testing/testing.install
index 192704d..19092d4 100644
--- a/profiles/testing/testing.install
+++ b/profiles/testing/testing.install
@@ -8,8 +8,4 @@
 function testing_install() {
   // Allow visitor account creation, but with administrative approval.
   variable_set('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL);
-
-  // Enable default permissions for system roles.
-  user_role_grant_permissions(DRUPAL_ANONYMOUS_RID, array('access content'));
-  user_role_grant_permissions(DRUPAL_AUTHENTICATED_RID, array('access content'));
 }
