diff --git a/core/includes/config.inc b/core/includes/config.inc
index c6435b3..1e638ca 100644
--- a/core/includes/config.inc
+++ b/core/includes/config.inc
@@ -1,7 +1,10 @@
 <?php
 
+use Drupal\Core\Config\Config;
 use Drupal\Core\Config\DatabaseStorage;
 use Drupal\Core\Config\FileStorage;
+use Drupal\Core\Config\NullStorage;
+use Drupal\Core\Config\StorageInterface;
 
 /**
  * @file
@@ -20,13 +23,21 @@ use Drupal\Core\Config\FileStorage;
 function config_install_default_config($module) {
   $module_config_dir = drupal_get_path('module', $module) . '/config';
   if (is_dir($module_config_dir)) {
-    $database_storage = new DatabaseStorage();
-    $module_file_storage = new FileStorage(array('directory' => $module_config_dir));
+    $source_storage = new FileStorage(array('directory' => $module_config_dir));
+    $target_storage = new DatabaseStorage();
+    $null_storage = new NullStorage();
 
-    foreach ($module_file_storage->listAll() as $config_name) {
-      $data = $module_file_storage->read($config_name);
-      $database_storage->write($config_name, $data);
+    // Upon module installation, only new config objects need to be created.
+    // config_sync_get_changes() would potentially perform a diff of hundreds or
+    // even thousands of config objects that happen to be contained in the
+    // active store. We leverage the NullStorage to avoid that needless
+    // computation of differences.
+    $config_changes = config_sync_get_changes($source_storage, $null_storage);
+    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);
   }
 }
 
@@ -57,3 +68,111 @@ function config($name) {
   return drupal_container()->get('config.factory')->get($name)->load();
 }
 
+/**
+ * Returns a list of differences between configuration storages.
+ *
+ * @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.
+ *
+ * @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) {
+  $source_names = $source_storage->listAll();
+  $target_names = $target_storage->listAll();
+  $config_changes = array(
+    'create' => array_diff($source_names, $target_names),
+    'change' => array(),
+    'delete' => array_diff($target_names, $source_names),
+  );
+  foreach (array_intersect($source_names, $target_names) as $name) {
+    $source_config_data = $source_storage->read($name);
+    $target_config_data = $target_storage->read($name);
+    if ($source_config_data != $target_config_data) {
+      $config_changes['change'][] = $name;
+    }
+  }
+
+  // Do not trigger subsequent synchronization operations if there are no
+  // changes in either category.
+  if (empty($config_changes['create']) && empty($config_changes['change']) && empty($config_changes['delete'])) {
+    return FALSE;
+  }
+  return $config_changes;
+}
+
+/**
+ * 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.
+ *
+ * @param array $config_changes
+ *   An array of changes to be loaded.
+ * @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.
+ *
+ * @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) {
+  $storage_dispatcher = drupal_container()->get('config.storage.dispatcher');
+
+  // Allow modules to take over configuration change operations for
+  // higher-level configuration data.
+  // First pass deleted, then new, and lastly changed configuration, in order to
+  // handle dependencies correctly.
+  foreach (array('delete', 'create', 'change') as $op) {
+    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')) {
+        $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);
+      }
+      if (!empty($handled_by_module)) {
+        unset($config_changes[$op][$key]);
+      }
+    }
+  }
+  return $config_changes;
+}
diff --git a/core/lib/Drupal/Core/Config/NullStorage.php b/core/lib/Drupal/Core/Config/NullStorage.php
new file mode 100644
index 0000000..54554c9
--- /dev/null
+++ b/core/lib/Drupal/Core/Config/NullStorage.php
@@ -0,0 +1,61 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Config\NullStorage.
+ */
+
+namespace Drupal\Core\Config;
+
+/**
+ * Defines the Null storage controller.
+ */
+class NullStorage implements StorageInterface {
+  /**
+   * Implements Drupal\Core\Config\StorageInterface::__construct().
+   */
+  public function __construct(array $options = array()) {
+  }
+
+  /**
+   * Implements Drupal\Core\Config\StorageInterface::read().
+   */
+  public function read($name) {
+    return array();
+  }
+
+  /**
+   * Implements Drupal\Core\Config\StorageInterface::write().
+   */
+  public function write($name, array $data) {
+    return FALSE;
+  }
+
+  /**
+   * Implements Drupal\Core\Config\StorageInterface::delete().
+   */
+  public function delete($name) {
+    return FALSE;
+  }
+
+  /**
+   * Implements Drupal\Core\Config\StorageInterface::encode().
+   */
+  public static function encode($data) {
+    return $data;
+  }
+
+  /**
+   * Implements Drupal\Core\Config\StorageInterface::decode().
+   */
+  public static function decode($raw) {
+    return $raw;
+  }
+
+  /**
+   * Implements Drupal\Core\Config\StorageInterface::listAll().
+   */
+  public function listAll($prefix = '') {
+    return array();
+  }
+}
diff --git a/core/modules/config/config.api.php b/core/modules/config/config.api.php
new file mode 100644
index 0000000..8cfa336
--- /dev/null
+++ b/core/modules/config/config.api.php
@@ -0,0 +1,63 @@
+<?php
+
+/**
+ * @file
+ * Hooks provided by the Configuration module.
+ */
+
+/**
+ * @defgroup config_hooks Configuration system hooks
+ * @{
+ * @todo Overall description of the configuration system.
+ * @}
+ */
+
+/**
+ * Synchronize configuration changes.
+ *
+ * This callback is invoked when configuration is synchronized between storages
+ * and allows a module to take over the synchronization of configuration data.
+ *
+ * Modules should implement this callback if they manage configuration data
+ * (such as image styles, node types, or fields), which needs to be
+ * prepared and passed through module API functions to properly handle a
+ * configuration change.
+ *
+ * @param string $op
+ *   The operation to perform for the configuration data; one of 'create',
+ *   'delete', or 'change'.
+ * @param string $name
+ *   The name of the configuration object.
+ * @param Drupal\Core\Config\Config $new_config
+ *   A configuration object containing the new configuration data.
+ * @param Drupal\Core\Config\Config $old_config
+ *   A configuration object containing the old configuration data.
+ */
+function MODULE_config_import($op, $name, $new_config, $old_config) {
+  // Only configurable thingies require custom handling. Any other module
+  // settings can be synchronized directly.
+  if (strpos($name, 'config_test.dynamic.') !== 0) {
+    return FALSE;
+  }
+
+  if ($op == 'delete') {
+    // @todo image_style_delete() supports the notion of a "replacement style"
+    //   to be used by other modules instead of the deleted style. Essential!
+    //   But that is impossible currently, since the config system only knows
+    //   about deleted and added changes. Introduce an 'old_ID' key within
+    //   config objects as a standard?
+    $config_test = new ConfigTest($old_config);
+    $config_test->delete();
+  }
+  if ($op == 'create') {
+    $config_test = new ConfigTest($new_config);
+    $config_test->save();
+  }
+  if ($op == 'change') {
+    $config_test = new ConfigTest($new_config);
+    $config_test->setOriginal($old_config);
+    $config_test->save();
+  }
+  return TRUE;
+}
+
diff --git a/core/modules/image/image.module b/core/modules/image/image.module
index f3bf83d..28afd0b 100644
--- a/core/modules/image/image.module
+++ b/core/modules/image/image.module
@@ -500,6 +500,35 @@ function image_path_flush($path) {
 }
 
 /**
+ * Implements hook_config_import().
+ */
+function image_config_import($op, $name, $new_config, $old_config) {
+  // Only image styles require custom handling. Any other module settings can be
+  // synchronized directly.
+  if (strpos($name, 'image.style.') !== 0) {
+    return FALSE;
+  }
+
+  if ($op == 'delete') {
+    // @todo image_style_delete() supports the notion of a "replacement style"
+    //   to be used by other modules instead of the deleted style. Essential!
+    //   But that is impossible currently, since the config system only knows
+    //   about deleted and added changes. Introduce an 'old_ID' key within
+    //   config objects as a standard?
+    $style = $old_config->get();
+    return image_style_delete($style);
+  }
+  if ($op == 'create') {
+    $style = $new_config->get();
+    return image_style_save($style);
+  }
+  if ($op == 'change') {
+    $style = $new_config->get();
+    return image_style_save($style);
+  }
+}
+
+/**
  * Get an array of all styles and their settings.
  *
  * @return
