diff --git a/includes/common.inc b/includes/common.inc
index d0649d7..e1c3174 100644
--- a/includes/common.inc
+++ b/includes/common.inc
@@ -7129,7 +7129,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 779b668..db75ae6 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/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 a144813..57f36a0 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('variables')
+    ->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 78be97d..30f6b1c 100644
--- a/modules/node/node.module
+++ b/modules/node/node.module
@@ -3881,6 +3881,27 @@ function node_modules_enabled($modules) {
 }
 
 /**
+ * Implements hook_modules_disabled().
+ */
+function node_modules_disabled($modules) {
+  foreach ($modules as $module) {
+    // @todo module_exists() is always FALSE at this point. Need a hook_modules_pre_disabled()?
+    if (1 || 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);
+      }
+    }
+  }
+
+  // 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/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 9dbab80..eb5fb11 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,
-    ),
-  );
+    );
+  }
   shortcut_set_save($shortcut_set);
 }
 
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/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
