diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigInstallTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigInstallTest.php
index b549119..147be46 100644
--- a/core/modules/config/lib/Drupal/config/Tests/ConfigInstallTest.php
+++ b/core/modules/config/lib/Drupal/config/Tests/ConfigInstallTest.php
@@ -7,12 +7,12 @@
 
 namespace Drupal\config\Tests;
 
-use Drupal\simpletest\DrupalUnitTestBase;
+use Drupal\simpletest\WebTestBase;
 
 /**
  * Tests installation of configuration objects in installation functionality.
  */
-class ConfigInstallTest extends DrupalUnitTestBase {
+class ConfigInstallTest extends WebTestBase {
   public static function getInfo() {
     return array(
       'name' => 'Installation functionality',
@@ -26,42 +26,263 @@ function setUp() {
 
     // Ensure the global variable being asserted by this test does not exist;
     // a previous test executed in this request/process might have set it.
+    unset($GLOBALS['hook_config_import']);
     unset($GLOBALS['hook_config_test']);
   }
 
   /**
-   * Tests module installation.
+   * Tests installing and uninstalling a module that provides default config.
    */
   function testModuleInstallation() {
     $default_config = 'config_test.system';
     $default_configuration_entity = 'config_test.dynamic.default';
 
-    // Verify that default module config does not exist before installation yet.
-    $config = config($default_config);
-    $this->assertIdentical($config->isNew(), TRUE);
-    $config = config($default_configuration_entity);
-    $this->assertIdentical($config->isNew(), TRUE);
+    // Verify that default module config does not exist before installation.
+    $this->assertNoConfig($default_config, 'after installing the module');
+    $this->assertNoConfig($default_configuration_entity, 'after installing the module');
 
     // Install the test module.
-    $this->enableModules(array('config_test'));
+    module_enable(array('config_test'));
 
     // Verify that default module config exists.
-    $config = config($default_config);
-    $this->assertIdentical($config->isNew(), FALSE);
-    $config = config($default_configuration_entity);
-    $this->assertIdentical($config->isNew(), FALSE);
-
-    // Verify that configuration import callback was invoked for the dynamic
-    // configuration entity.
-    $this->assertTrue($GLOBALS['hook_config_import']);
-
-    // Verify that config_test API hooks were invoked for the dynamic default
-    // configuration entity.
-    $this->assertFalse(isset($GLOBALS['hook_config_test']['load']));
-    $this->assertTrue(isset($GLOBALS['hook_config_test']['presave']));
-    $this->assertTrue(isset($GLOBALS['hook_config_test']['insert']));
-    $this->assertFalse(isset($GLOBALS['hook_config_test']['update']));
-    $this->assertFalse(isset($GLOBALS['hook_config_test']['predelete']));
-    $this->assertFalse(isset($GLOBALS['hook_config_test']['delete']));
+    $this->assertConfig($default_config, 'after installing the module');
+    $this->assertConfig($default_configuration_entity, 'after installing the module');
+
+    // Confirm that hook_config_import_create() was invoked for the provided
+    // default config entity.
+    $import_hooks = array(
+      'create' => TRUE,
+      'change' => FALSE,
+      'delete' => FALSE,
+    );
+    // $GLOBALS['hook_config_import'] is set in config_test.module.
+    $this->assertConfigHooks($GLOBALS['hook_config_import'], $import_hooks, 'after installing the module');
+
+    // Confirm that the insert and presave config_test API hooks were invoked
+    // for the provided default config entity.
+    $api_hooks = array(
+      'load' => FALSE,
+      'presave' => TRUE,
+      'insert' => TRUE,
+      'update' => FALSE,
+      'predelete' => FALSE,
+      'delete' => FALSE,
+    );
+    // $GLOBALS['hook_config_test'] is set in config_test.hooks.inc.
+    $this->assertConfigHooks($GLOBALS['hook_config_test'], $api_hooks, 'after installing the module');
+
+    // Disable the module and verify that the config is not removed.
+    module_disable(array('config_test'));
+    $this->assertConfig($default_config, 'after disabling the module');
+    $this->assertConfig($default_configuration_entity, 'after disabling the module');
+
+    // Uninstall the module and verify that the config was removed.
+    module_uninstall(array('config_test'));
+    $this->assertNoConfig($default_config, 'after uninstalling the module');
+    $this->assertNoConfig($default_configuration_entity, 'after uninstalling the module');
+  }
+
+  /**
+   * Tests installing config_test_extension_test before config_test.
+   *
+   * config_test_extension_test.module provides default configuration in
+   * config_test.module's namespace.
+   */
+  function testExtensionInstallationFirst() {
+    // Verify that default module config does not exist before installation.
+    $extension_config_entity = 'config_test.dynamic.extension_default';
+    $this->assertNoConfig($extension_config_entity, 'before installing either module');
+
+    // Install the extension module.
+    module_enable(array('config_test_extension_test'));
+
+    // The config_test API is not available, so configuration objects in its
+    // namespace should not be installed.
+    $this->assertNoConfig($extension_config_entity, 'after installing config_test_extension_test first');
+
+    // Install the base API module.
+    module_enable(array('config_test'));
+
+    // The extension module's default config should now be installed.
+    $this->assertConfig($extension_config_entity, 'after installing config_test second');
+
+    // Confirm that hook_config_import_create() was invoked for the provided
+    // default config entity.
+    $import_hooks = array(
+      'create' => TRUE,
+      'change' => FALSE,
+      'delete' => FALSE,
+    );
+    // $GLOBALS['hook_config_import'] is set in config_test.module.
+    $this->assertConfigHooks($GLOBALS['hook_config_import'], $import_hooks, 'after installing config_test second');
+
+    // Confirm that the insert and presave config_test API hooks were invoked
+    // for the provided default config entity.
+    $api_hooks = array(
+      'load' => FALSE,
+      'presave' => TRUE,
+      'insert' => TRUE,
+      'update' => FALSE,
+      'predelete' => FALSE,
+      'delete' => FALSE,
+    );
+    // $GLOBALS['hook_config_test'] is set in config_test.hooks.inc.
+    $this->assertConfigHooks($GLOBALS['hook_config_test'], $api_hooks, 'after installing config_test second');
+
+    // Uninstall the extension module.
+    module_enable(array('config_test_extension_test'));
+
+    // @todo Should the configuration be available here or not?
   }
+
+  /**
+   * Tests installing config_test_extension_test after config_test.
+   *
+   * config_test_extension_test.module provides default configuration in
+   * config_test.module's namespace.
+   */
+  function testExtensionInstallationSecond() {
+    // Verify that default module config does not exist before installation.
+    $extension_config_entity = 'config_test.dynamic.extension_default';
+    $this->assertNoConfig($extension_config_entity, 'before installing either module');
+
+    // Install the base API module.
+    module_enable(array('config_test'));
+
+    // The config_test_extension_test module is not yet installed, so its
+    // default configuration is not installed.
+    $this->assertNoConfig($extension_config_entity, 'after installing config_test first');
+
+    // Install the extension module.
+    module_enable(array('config_test_extension_test'));
+
+    // The extension module's default config should now be installed.
+    $this->assertConfig($extension_config_entity, 'after installing config_test_extension_test second');
+
+    // Confirm that hook_config_import_create() was invoked for the provided
+    // default config entity.
+    $import_hooks = array(
+      'create' => TRUE,
+      'change' => FALSE,
+      'delete' => FALSE,
+    );
+    // $GLOBALS['hook_config_import'] is set in config_test.module.
+    $this->assertConfigHooks($GLOBALS['hook_config_import'], $import_hooks, 'after installing config_test_extension_test second');
+
+    // Confirm that the insert and presave config_test API hooks were invoked
+    // for the provided default config entity.
+    $api_hooks = array(
+      'load' => FALSE,
+      'presave' => TRUE,
+      'insert' => TRUE,
+      'update' => FALSE,
+      'predelete' => FALSE,
+      'delete' => FALSE,
+    );
+    // $GLOBALS['hook_config_test'] is set in config_test.hooks.inc.
+    $this->assertConfigHooks($GLOBALS['hook_config_test'], $api_hooks, 'after installing config_test_extension_test second');
+
+    // Uninstall the base API module.
+    module_uninstall(array('config_test'));
+
+    // The test configuration should no longer be available.
+    $this->assertNoConfig($extension_config_entity, 'after uninstalling config_test');
+  }
+
+  /**
+   * Asserts that a set of config hooks were invoked or not from passed data.
+   *
+   * @param array $actual
+   *   An array of the hooks that were invoked (set in globals), with the key
+   *   indicating the type of hook and the value as the hook implementation
+   *   if it was invoked.
+   * @param array $expected
+   *   An array indicating whether each hook was expected to be invoked or not,
+   *   with the key indicating the type of hook and the value a Boolean
+   *   indicating whether the hook should be invoked.
+   * @param string $when
+   *   (optional) A text string describing when the assertion was called.
+   *
+   * @see config_test.module
+   * @see config_test.hooks.inc
+   */
+  function assertConfigHooks(array $actual, array $expected, $when = '') {
+    foreach ($expected as $hook => $value) {
+      if (!empty($actual[$hook])) {
+        $function = $actual[$hook];
+      }
+      else {
+        $function = $hook . ' hook';
+      }
+      $this->assertTrue(
+        // The hook flag should evaluate to empty if it was not invoked.
+        ($value != empty($actual[$hook])),
+        format_string(
+          '%hook was @invoked @when.',
+          array(
+            '%hook' => $function,
+            '@invoked' => $value ? 'invoked' : 'not invoked',
+            '@when' => $when,
+          )
+        )
+      );
+    }
+  }
+
+  /**
+   * Asserts that the configuration with the given name is installed.
+   *
+   * @param string $name
+   *   The full configuration object name to check, e.g. module.foo.bar.
+   * @param string $when
+   *   (optional) A text string describing when the assertion was called.
+   */
+  function assertConfig($name, $when = '') {
+    $config = config($name);
+    $file = config_get_config_directory() . '/' . $name . '.yml';
+    $this->assertIdentical($config->isNew(), FALSE, format_string(
+      '%config config object exists @when.',
+      array(
+        '%config' => $name,
+        '@when' => $when,
+      )
+    ));
+    $this->assertTrue(file_exists($file), format_string(
+      'File for %config found in %file @when.',
+      array(
+        '%config' => $name,
+        '%file' => $file,
+        '@when' => $when,
+      )
+    ));
+  }
+
+  /**
+   * Asserts that the configuration with the given name is not installed.
+   *
+   * @param string $name
+   *   The full configuration object name to check, e.g. module.foo.bar.
+   * @param string $when
+   *   (optional) A text string describing when the assertion was called.
+   */
+  function assertNoConfig($name, $when = '') {
+    $file = config_get_config_directory() . '/' . $name . '.yml';
+    $config = config($name);
+    $this->assertIdentical($config->isNew(), TRUE, format_string(
+      '%config config object does not exist @when.',
+      array(
+        '%config' => $name,
+        '@when' => $when,
+      )
+    ));
+    $this->assertFalse(file_exists($file), format_string(
+      'File for %config not found in %file @when.',
+      array(
+        '%config' => $name,
+        '%file' => $file,
+        '@when' => $when,
+      )
+    ));
+  }
+
 }
diff --git a/core/modules/config/tests/config_test/config_test.module b/core/modules/config/tests/config_test/config_test.module
index 96d4aa0..9d465db 100644
--- a/core/modules/config/tests/config_test/config_test.module
+++ b/core/modules/config/tests/config_test/config_test.module
@@ -17,7 +17,7 @@ function config_test_config_import_create($name, $new_config, $old_config) {
     return FALSE;
   }
   // Set a global value we can check in test code.
-  $GLOBALS['hook_config_import'] = __FUNCTION__;
+  $GLOBALS['hook_config_import']['create'] = __FUNCTION__;
 
   $config_test = entity_create('config_test', $new_config->get());
   $config_test->save();
@@ -32,7 +32,7 @@ function config_test_config_import_change($name, $new_config, $old_config) {
     return FALSE;
   }
   // Set a global value we can check in test code.
-  $GLOBALS['hook_config_import'] = __FUNCTION__;
+  $GLOBALS['hook_config_import']['change'] = __FUNCTION__;
 
   // @todo Make this less ugly.
   list(, , $id) = explode('.', $name);
@@ -62,7 +62,7 @@ function config_test_config_import_delete($name, $new_config, $old_config) {
     return FALSE;
   }
   // Set a global value we can check in test code.
-  $GLOBALS['hook_config_import'] = __FUNCTION__;
+  $GLOBALS['hook_config_import']['delete'] = __FUNCTION__;
 
   // @todo Make this less ugly.
   list(, , $id) = explode('.', $name);
diff --git a/core/modules/config/tests/config_test_extension_test/config/config_test.dynamic.extension_default.yml b/core/modules/config/tests/config_test_extension_test/config/config_test.dynamic.extension_default.yml
new file mode 100644
index 0000000..a024b46
--- /dev/null
+++ b/core/modules/config/tests/config_test_extension_test/config/config_test.dynamic.extension_default.yml
@@ -0,0 +1,2 @@
+id: extension_default
+label: Extension module default
diff --git a/core/modules/config/tests/config_test_extension_test/config_test_extension_test.info b/core/modules/config/tests/config_test_extension_test/config_test_extension_test.info
new file mode 100644
index 0000000..1057788
--- /dev/null
+++ b/core/modules/config/tests/config_test_extension_test/config_test_extension_test.info
@@ -0,0 +1,6 @@
+name = config_test extension test module
+description = Provides default configuration in the config_test namespace.
+package = Core
+version = VERSION
+core = 8.x
+hidden = TRUE
diff --git a/core/modules/config/tests/config_test_extension_test/config_test_extension_test.module b/core/modules/config/tests/config_test_extension_test/config_test_extension_test.module
new file mode 100644
index 0000000..c471336
--- /dev/null
+++ b/core/modules/config/tests/config_test_extension_test/config_test_extension_test.module
@@ -0,0 +1,8 @@
+<?php
+
+/**
+ * @file
+ * Extension module that provides default configuration in another namespace.
+ *
+ * @see config_test.module
+ */
