diff --git a/core/includes/config.inc b/core/includes/config.inc
index 51476b7..747388c 100644
--- a/core/includes/config.inc
+++ b/core/includes/config.inc
@@ -36,8 +36,7 @@ function config_install_default_config($module) {
     if (empty($config_changes)) {
       return;
     }
-    $remaining_changes = config_import_invoke_owner($config_changes, $source_storage, $target_storage);
-    config_sync_changes($remaining_changes, $source_storage, $target_storage);
+    config_import_execute($config_changes, $source_storage, $target_storage);
   }
 }
 
@@ -105,31 +104,7 @@ function config_sync_get_changes(StorageInterface $source_storage, StorageInterf
 }
 
 /**
- * Writes an array of config file changes from a source storage to a target storage.
- *
- * @param array $config_changes
- *   An array of changes to be written.
- * @param Drupal\Core\Config\StorageInterface $source_storage
- *   The storage to synchronize configuration from.
- * @param Drupal\Core\Config\StorageInterface $target_storage
- *   The storage to synchronize configuration to.
- */
-function config_sync_changes(array $config_changes, StorageInterface $source_storage, StorageInterface $target_storage) {
-  foreach (array('delete', 'create', 'change') as $op) {
-    foreach ($config_changes[$op] as $name) {
-      if ($op == 'delete') {
-        $target_storage->delete($name);
-      }
-      else {
-        $data = $source_storage->read($name);
-        $target_storage->write($name, $data);
-      }
-    }
-  }
-}
-
-/**
- * Invokes MODULE_config_import() callbacks for configuration changes.
+ * Execute the sync.
  *
  * @param array $config_changes
  *   An array of changes to be loaded.
@@ -140,7 +115,7 @@ function config_sync_changes(array $config_changes, StorageInterface $source_sto
  *
  * @todo Add support for other extension types; e.g., themes etc.
  */
-function config_import_invoke_owner(array $config_changes, StorageInterface $source_storage, StorageInterface $target_storage) {
+function config_import_execute(array $config_changes, StorageInterface $source_storage, StorageInterface $target_storage) {
   $storage_dispatcher = drupal_container()->get('config.storage.dispatcher');
 
   // Allow modules to take over configuration change operations for
@@ -151,26 +126,23 @@ function config_import_invoke_owner(array $config_changes, StorageInterface $sou
     foreach ($config_changes[$op] as $key => $name) {
       // Extract owner from configuration object name.
       $module = strtok($name, '.');
-      // Check whether the module implements hook_config_import() and ask it to
-      // handle the configuration change.
-      $handled_by_module = FALSE;
-      if (module_hook($module, 'config_import_' . $op)) {
-        $old_config = new Config($storage_dispatcher);
-        $old_config
-          ->setName($name)
-          ->load();
+      $old_config = new Config($storage_dispatcher);
+      $old_config
+        ->setName($name)
+        ->load();
 
-        $data = $source_storage->read($name);
-        $new_config = new Config($storage_dispatcher);
-        $new_config->setName($name);
-        if ($data !== FALSE) {
-          $new_config->setData($data);
-        }
-
-        $handled_by_module = module_invoke($module, 'config_import_' . $op, $name, $new_config, $old_config);
+      $data = $source_storage->read($name);
+      $new_config = new Config($storage_dispatcher);
+      $new_config->setName($name);
+      if ($data !== FALSE) {
+        $new_config->setData($data);
       }
-      if (!empty($handled_by_module)) {
-        unset($config_changes[$op][$key]);
+      module_invoke($module, 'config_import_' . $op, $name, $new_config, $old_config);
+      if ($op == 'delete') {
+        $target_storage->delete($name);
+      }
+      else {
+        $target_storage->write($name, $new_config->get());
       }
     }
   }
diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigInstallTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigInstallTest.php
index 7ec6d8e..a4d573f 100644
--- a/core/modules/config/lib/Drupal/config/Tests/ConfigInstallTest.php
+++ b/core/modules/config/lib/Drupal/config/Tests/ConfigInstallTest.php
@@ -46,5 +46,9 @@ class ConfigInstallTest extends WebTestBase {
     // Verify that configuration import callback was invoked for the dynamic
     // thingie.
     $this->assertTrue($GLOBALS['hook_config_import']);
+
+    // Verify that the imported configuration object was saved through the
+    // module API.
+    $this->assertIdentical($config->get('version'), VERSION);
   }
 }
diff --git a/core/modules/config/tests/config_test/config/config_test.dynamic.default.yml b/core/modules/config/tests/config_test/config/config_test.dynamic.default.yml
index 3e50e3b..3dd16eb 100644
--- a/core/modules/config/tests/config_test/config/config_test.dynamic.default.yml
+++ b/core/modules/config/tests/config_test/config/config_test.dynamic.default.yml
@@ -1,2 +1,3 @@
 id: default
 label: Default
+version: 1.0
diff --git a/core/modules/config/tests/config_test/config_test.module b/core/modules/config/tests/config_test/config_test.module
index 6fd84a2..644655f 100644
--- a/core/modules/config/tests/config_test/config_test.module
+++ b/core/modules/config/tests/config_test/config_test.module
@@ -12,7 +12,15 @@ function config_test_config_import_create($name, $new_config, $old_config) {
   // Set a global value we can check in test code.
   $GLOBALS['hook_config_import'] = __FUNCTION__;
 
-  $new_config->save();
+  // This config object has been saved through the current module API.
+  // There is no guarantee that the module API uses $new_config directly,
+  // nor a hard requirement for configurable thingies to be based on Config
+  // objects. Therefore, mock these possible scenarios.
+  $config = config($name, $new_config->get());
+  // Therefore, its version property should equal the current version.
+  $config->set('version', VERSION);
+
+  $config->save();
   return TRUE;
 }
 
