diff --git a/core/includes/config.inc b/core/includes/config.inc
index c89537d..b949199 100644
--- a/core/includes/config.inc
+++ b/core/includes/config.inc
@@ -29,27 +29,27 @@ function config_install_default_config($type, $name) {
     $source_storage = new FileStorage($config_dir);
     $target_storage = drupal_container()->get('config.storage');
 
+    // Ignore manifest files.
+    $config_changes = config_sync_get_changes($source_storage, $target_storage, FALSE);
+
     // If this module defines any ConfigEntity types, then create a manifest file
     // for each of them with a listing of the objects it maintains.
     foreach (config_get_module_config_entities($name) as $entity_type => $entity_info) {
       $manifest_config = config('manifest.' . $entity_info['config_prefix']);
-      $manifest_data = array();
       foreach ($source_storage->listAll($entity_info['config_prefix']) as $config_name) {
         list(, , $id) = explode('.', $config_name);
-        $manifest_data[$id]['name'] = $config_name;
+        $manifest_config->set("$id.name", $config_name);
       }
-      $manifest_config->setData($manifest_data)->save();
+      $manifest_config->save();
     }
 
-    $config_changes = array(
-      'delete' => array(),
-      'create' => array(),
-      'change' => array(),
-    );
-    $config_changes['create'] = $source_storage->listAll();
     if (empty($config_changes['create'])) {
       return;
     }
+    // Do not overwrite or delete pre-existing configuration.
+    $config_changes['change'] = array();
+    $config_changes['delete'] = array();
+
     $remaining_changes = config_import_invoke_owner($config_changes, $source_storage, $target_storage);
     config_sync_changes($remaining_changes, $source_storage, $target_storage);
   }
@@ -112,44 +112,51 @@ function config($name) {
  *   The storage to synchronize configuration from.
  * @param Drupal\Core\Config\StorageInterface $target_storage
  *   The storage to synchronize configuration to.
+ * @param bool $require_manifest
+ *   (optional) Whether to determine changes based on manifest files. Defaults
+ *   to TRUE.
  *
  * @return array|bool
  *   An assocative array containing the differences between source and target
  *   storage, or FALSE if there are no differences.
  */
-function config_sync_get_changes(StorageInterface $source_storage, StorageInterface $target_storage) {
+function config_sync_get_changes(StorageInterface $source_storage, StorageInterface $target_storage, $require_manifest = TRUE) {
+  $config_changes = array(
+    'create' => array(),
+    'change' => array(),
+    'delete' => array(),
+  );
+  $all_source_names = $source_storage->listAll();
+  $all_target_names = $target_storage->listAll();
+
   // Config entities maintain 'manifest' files that list the objects they
   // are currently handling. Each file is a simple indexed array of config
   // object names. In order to generate a list of objects that have been
   // created or deleted we need to open these files in both the source and
   // target storage, generate an array of the objects, and compare them.
-  $source_config_data = array();
-  $target_config_data = array();
-  foreach ($source_storage->listAll('manifest') as $name) {
-    if ($source_manifest_data = $source_storage->read($name)) {
-      $source_config_data = array_merge($source_config_data, $source_manifest_data);
+  if ($require_manifest) {
+    $source_config_data = array();
+    $target_config_data = array();
+    foreach ($source_storage->listAll('manifest') as $name) {
+      if ($source_manifest_data = $source_storage->read($name)) {
+        $source_config_data = array_merge($source_config_data, $source_manifest_data);
+      }
+      if ($target_manifest_data = $target_storage->read($name)) {
+        $target_config_data = array_merge($target_config_data, $target_manifest_data);
+      }
     }
-
-    if ($target_manifest_data = $target_storage->read($name)) {
-      $target_config_data = array_merge($target_config_data, $target_manifest_data);
+    foreach (array_diff_key($target_config_data, $source_config_data) as $name => $value) {
+      $config_changes['delete'][] = $value['name'];
+    }
+    foreach (array_diff_key($source_config_data, $target_config_data) as $name => $value) {
+      $config_changes['create'][] = $value['name'];
     }
   }
-
-  $config_changes = array(
-    'create' => array(),
-    'change' => array(),
-    'delete' => array(),
-  );
-
-  foreach (array_diff_key($target_config_data, $source_config_data) as $name => $value) {
-    $config_changes['delete'][] = $value['name'];
-  }
-
-  foreach (array_diff_key($source_config_data, $target_config_data) as $name => $value) {
-    $config_changes['create'][] = $value['name'];
+  else {
+    $config_changes['delete'] = array_diff($all_target_names, $all_source_names);
+    $config_changes['create'] = array_diff($all_source_names, $all_target_names);
   }
-
-  foreach (array_intersect($source_storage->listAll(), $target_storage->listAll()) as $name) {
+  foreach (array_intersect($all_source_names, $all_target_names) as $name) {
     // Ignore manifest files
     if (substr($name, 0, 9) != 'manifest.') {
       $source_config_data = $source_storage->read($name);
diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigInstallTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigInstallTest.php
index b549119..84cca89 100644
--- a/core/modules/config/lib/Drupal/config/Tests/ConfigInstallTest.php
+++ b/core/modules/config/lib/Drupal/config/Tests/ConfigInstallTest.php
@@ -64,4 +64,68 @@ function testModuleInstallation() {
     $this->assertFalse(isset($GLOBALS['hook_config_test']['predelete']));
     $this->assertFalse(isset($GLOBALS['hook_config_test']['delete']));
   }
+
+  /**
+   * Tests module re-installation.
+   */
+  function testIntegrationModuleReinstallation() {
+    $default_config = 'config_integration_test.settings';
+    $default_configuration_entity = 'config_test.dynamic.config_integration_test';
+
+    // Install the config_test module we're integrating with.
+    $this->enableModules(array('config_test'));
+
+    // Verify the configuration does not exist prior to installation.
+    $config_static = config($default_config);
+    $this->assertIdentical($config_static->isNew(), TRUE);
+    $config_entity = config($default_configuration_entity);
+    $this->assertIdentical($config_entity->isNew(), TRUE);
+
+    // Install the integration module.
+    $this->enableModules(array('config_integration_test'));
+
+    // Verify that default module config exists.
+    $config_static = config($default_config);
+    $this->assertIdentical($config_static->isNew(), FALSE);
+    $this->assertIdentical($config_static->get('foo'), 'default setting');
+    $config_entity = config($default_configuration_entity);
+    $this->assertIdentical($config_entity->isNew(), FALSE);
+    $this->assertIdentical($config_entity->get('label'), 'Default integration config label');
+
+    // Customize both configuration objects.
+    $config_static->set('foo', 'customized setting')->save();
+    $config_entity->set('label', 'Customized integration config label')->save();
+
+    // @todo FIXME: Setting config keys WITHOUT SAVING retains the changed config
+    //   object in memory. Every new call to config() MUST revert in-memory changes
+    //   that haven't been saved!
+    //   In other words: This test passes even without this reset, but it shouldn't.
+    $this->container->get('config.factory')->reset();
+
+    // Disable and uninstall the integration module.
+    $this->disableModules(array('config_integration_test'), TRUE);
+
+    // Verify the integration module's config was uninstalled.
+    $config_static = config($default_config);
+    $this->assertIdentical($config_static->isNew(), TRUE);
+
+    // Verify the integration config still exists.
+    $config_entity = config($default_configuration_entity);
+    $this->assertIdentical($config_entity->isNew(), FALSE);
+    $this->assertIdentical($config_entity->get('label'), 'Customized integration config label');
+
+    // Reinstall the integration module.
+    $this->enableModules(array('config_integration_test'));
+
+    // Verify the integration module's config was re-installed.
+    $config_static = config($default_config);
+    $this->assertIdentical($config_static->isNew(), FALSE);
+    $this->assertIdentical($config_static->get('foo'), 'default setting');
+
+    // Verify the customized integration config still exists.
+    $config_entity = config($default_configuration_entity);
+    $this->assertIdentical($config_entity->isNew(), FALSE);
+    $this->assertIdentical($config_entity->get('label'), 'Customized integration config label');
+  }
+
 }
diff --git a/core/modules/config/tests/config_integration_test/config/config_integration_test.settings.yml b/core/modules/config/tests/config_integration_test/config/config_integration_test.settings.yml
new file mode 100644
index 0000000..1b33ac0
--- /dev/null
+++ b/core/modules/config/tests/config_integration_test/config/config_integration_test.settings.yml
@@ -0,0 +1 @@
+foo: 'default setting'
diff --git a/core/modules/config/tests/config_integration_test/config/config_test.dynamic.config_integration_test.yml b/core/modules/config/tests/config_integration_test/config/config_test.dynamic.config_integration_test.yml
new file mode 100644
index 0000000..f87b942
--- /dev/null
+++ b/core/modules/config/tests/config_integration_test/config/config_test.dynamic.config_integration_test.yml
@@ -0,0 +1,2 @@
+id: config_integration_test
+label: 'Default integration config label'
diff --git a/core/modules/config/tests/config_integration_test/config_integration_test.info b/core/modules/config/tests/config_integration_test/config_integration_test.info
new file mode 100644
index 0000000..8a9db4b
--- /dev/null
+++ b/core/modules/config/tests/config_integration_test/config_integration_test.info
@@ -0,0 +1,6 @@
+name = ConfigTest integration
+package = Testing
+version = VERSION
+core = 8.x
+hidden = TRUE
+dependencies[] = config_test
diff --git a/core/modules/config/tests/config_integration_test/config_integration_test.module b/core/modules/config/tests/config_integration_test/config_integration_test.module
new file mode 100644
index 0000000..9c92696
--- /dev/null
+++ b/core/modules/config/tests/config_integration_test/config_integration_test.module
@@ -0,0 +1,6 @@
+<?php
+
+/**
+ * @file
+ * ConfigTest entity integration test module.
+ */
diff --git a/core/modules/config/tests/config_test/config_test.info b/core/modules/config/tests/config_test/config_test.info
index 3c0ca6b..b8ae2fc 100644
--- a/core/modules/config/tests/config_test/config_test.info
+++ b/core/modules/config/tests/config_test/config_test.info
@@ -1,5 +1,5 @@
-name = Configuration test module
-package = Core
+name = Configuration test
+package = Testing
 version = VERSION
 core = 8.x
 hidden = TRUE
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/DrupalUnitTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/DrupalUnitTestBase.php
index b09df75..919874e 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/DrupalUnitTestBase.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/DrupalUnitTestBase.php
@@ -211,11 +211,9 @@ protected function installSchema($module, $table) {
    *   implementation that is able to manage a fixed module list.
    */
   protected function enableModules(array $modules, $install = TRUE) {
-    // Set the modules in the fixed module_list().
-    $new_enabled = array();
     foreach ($modules as $module) {
+      // Set the module in the fixed module_list().
       $this->moduleList[$module]['filename'] = drupal_get_filename('module', $module);
-      $new_enabled[$module] = dirname($this->moduleList[$module]['filename']);
       module_list(NULL, $this->moduleList);
 
       // Call module_enable() to enable (install) the new module.
@@ -230,4 +228,35 @@ protected function enableModules(array $modules, $install = TRUE) {
     }
   }
 
+  /**
+   * Disables modules in this test.
+   *
+   * module_disable() disables the modules in the system.module configuration
+   * only, but that has no effect, since we are operating with a fixed module
+   * list.
+   *
+   * @param array $modules
+   *   A list of modules to disable. Dependencies are not resolved; i.e.,
+   *   multiple modules have to be specified with dependent modules first.
+   * @param bool $uninstall
+   *   (optional) Whether to uninstall the modules via module_uninstall().
+   *   Defaults to FALSE. If TRUE, the modules are only disabled.
+   *
+   * @todo Remove this method as soon as there is an Extensions service
+   *   implementation that is able to manage a fixed module list.
+   */
+  protected function disableModules(array $modules, $uninstall = FALSE) {
+    foreach ($modules as $module) {
+      // Call module_disable() to disable the module.
+      module_disable(array($module), FALSE);
+
+      // Unset the module in the fixed module_list().
+      unset($this->moduleList[$module]);
+      module_list(NULL, $this->moduleList);
+    }
+    if ($uninstall) {
+      module_uninstall($modules, FALSE);
+    }
+  }
+
 }
