diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index fa1335b..fc1de17 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -288,8 +288,6 @@ const REGISTRY_WRITE_LOOKUP_CACHE = 2;
  */
 const DRUPAL_PHP_FUNCTION_PATTERN = '[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*';
 
-require_once DRUPAL_ROOT . '/core/includes/config.inc';
-
 /**
  * Starts the timer with the specified name.
  *
@@ -2265,6 +2263,9 @@ function _drupal_bootstrap_configuration() {
 
   // Activate the class loader.
   drupal_classloader();
+
+  // Load the procedural configuration system helper functions.
+  require_once DRUPAL_ROOT . '/core/includes/config.inc';
 }
 
 /**
diff --git a/core/includes/config.inc b/core/includes/config.inc
index 8d0eea1..ce8f659 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\ConfigException;
 use Drupal\Core\Config\DatabaseStorage;
 use Drupal\Core\Config\FileStorage;
+use Drupal\Core\Config\StorageInterface;
 
 /**
  * @file
@@ -38,28 +41,23 @@ function config_get_config_directory() {
  */
 function config_install_default_config($module) {
   $module_config_dir = drupal_get_path('module', $module) . '/config';
-  $drupal_config_dir = config_get_config_directory();
-  if (is_dir(drupal_get_path('module', $module) . '/config')) {
-    $files = glob($module_config_dir . '/*.' . FileStorage::getFileExtension());
-    foreach ($files as $key => $file) {
-      // Load config data into the active store and write it out to the
-      // file system in the drupal config directory. Note the config name
-      // needs to be the same as the file name WITHOUT the extension.
-      $config_name = basename($file, '.' . FileStorage::getFileExtension());
-
-      $database_storage = new DatabaseStorage($config_name);
-      $file_storage = new FileStorage($config_name);
-      $file_storage->setPath($module_config_dir);
-      $database_storage->write($file_storage->read());
+  if (is_dir($module_config_dir)) {
+    $database_storage = new DatabaseStorage();
+    $module_file_storage = new FileStorage(array('directory' => $module_config_dir));
+
+    foreach ($module_file_storage->getNamesWithPrefix() as $config_name) {
+      $data = $module_file_storage->read($config_name);
+      $database_storage->write($config_name, $data);
     }
   }
 }
 
 /**
- * @todo http://drupal.org/node/1552396 renames this into config_load_all().
+ * @todo Modules need a way to access the active store, whatever it is.
  */
 function config_get_storage_names_with_prefix($prefix = '') {
-  return DatabaseStorage::getNamesWithPrefix($prefix);
+  $storage = new DatabaseStorage();
+  return $storage->getNamesWithPrefix($prefix);
 }
 
 /**
@@ -73,16 +71,214 @@ function config_get_storage_names_with_prefix($prefix = '') {
  *   The name of the configuration object to retrieve. The name corresponds to
  *   a configuration file. For @code config(book.admin) @endcode, the config
  *   object returned will contain the contents of book.admin configuration file.
- * @param $class
- *   The class name of the config object to be returned. Defaults to
- *   DrupalConfig.
  *
- * @return
- *   An instance of the class specified in the $class parameter.
+ * @return Drupal\Core\Config\Config
+ *   A configuration object.
+ */
+function config($name) {
+  return drupal_container()->get('config.factory')->get($name)->load();
+}
+
+/**
+ * Returns a list of differences between configuration storages.
  *
- * @todo Replace this with an appropriate factory / ability to inject in
- *   alternate storage engines..
+ * @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($name, $class = 'Drupal\Core\Config\DrupalConfig') {
-  return new $class(new DatabaseStorage($name));
+function config_sync_get_changes(StorageInterface $source_storage, StorageInterface $target_storage) {
+  $source_names = $source_storage->getNamesWithPrefix();
+  $target_names = $target_storage->getNamesWithPrefix();
+  $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;
 }
+
+/**
+ * Imports configuration from FileStorage to DatabaseStorage.
+ */
+function config_import() {
+  $config_changes = config_import_get_changes();
+  if (empty($config_changes)) {
+    return;
+  }
+
+  if (!lock_acquire(__FUNCTION__)) {
+    // Another request is synchronizing configuration.
+    // Return a negative result for UI purposes. We do not make a difference
+    // between an actual synchronization error and a failed lock, because a
+    // concurrent request synchronizing configuration is an edge-case in the
+    // first place and would mean that more than one developer or site builder
+    // attempts to do it without coordinating with others.
+    return FALSE;
+  }
+
+  try {
+    $remaining_changes = config_import_invoke_sync_hooks($config_changes);
+    config_import_save_changes($remaining_changes);
+    // Flush all caches and reset static variables after a successful import.
+    drupal_flush_all_caches();
+  }
+  catch (ConfigException $e) {
+    watchdog_exception('config_import', $e);
+    lock_release(__FUNCTION__);
+    return FALSE;
+  }
+  lock_release(__FUNCTION__);
+  return TRUE;
+}
+
+/**
+ * Returns a list of differences between FileStorage and DatabaseStorage.
+ *
+ * @see config_sync_get_changes()
+ */
+function config_import_get_changes() {
+  // @todo Leverage DI + config.storage.info.
+  $source_storage = new FileStorage();
+  $target_storage = new DatabaseStorage();
+
+  return config_sync_get_changes($source_storage, $target_storage);
+}
+
+/**
+ * Writes an array of config file changes to the active store.
+ *
+ * @param array $config_changes
+ *   An array of changes to be written.
+ */
+function config_import_save_changes(array $config_changes) {
+  // @todo Leverage DI + config.storage.info.
+  $source_storage = new FileStorage();
+  $target_storage = new DatabaseStorage();
+  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 hook_config_import() implementations for configuration changes.
+ *
+ * @param array $config_changes
+ *   An array of changes to be loaded.
+ */
+function config_import_invoke_sync_hooks(array $config_changes) {
+  // @todo Leverage DI + config.storage.info.
+  $source_storage = new FileStorage();
+  $target_storage = new DatabaseStorage();
+  $storage_manager = drupal_container()->get('config.storage.manager');
+
+  // 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_manager);
+        $old_config->setName($name);
+        try {
+          $old_config->load();
+        }
+        catch (ConfigException $e) {
+        }
+        try {
+          $data = $source_storage->read($name);
+        }
+        catch (ConfigException $e) {
+          $data = array();
+        }
+        $new_config = new Config($storage_manager);
+        $new_config->setName($name)->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;
+}
+
+/**
+ * Exports configuration from DatabaseStorage to FileStorage.
+ */
+function config_export() {
+  $config_changes = config_export_get_changes();
+  if (empty($config_changes)) {
+    return;
+  }
+  config_export_save_changes($config_changes);
+  return TRUE;
+}
+
+/**
+ * Returns a list of differences between DatabaseStorage and FileStorage.
+ *
+ * @see config_sync_get_changes()
+ */
+function config_export_get_changes() {
+  // @todo Leverage DI + config.storage.info.
+  $source_storage = new DatabaseStorage();
+  $target_storage = new FileStorage();
+
+  return config_sync_get_changes($source_storage, $target_storage);
+}
+
+/**
+ * Writes an array of configuration changes to FileStorage.
+ *
+ * @param array $config_changes
+ *   An array of changes to be written.
+ */
+function config_export_save_changes(array $config_changes) {
+  // @todo Leverage DI + config.storage.info.
+  $source_storage = new DatabaseStorage();
+  $target_storage = new FileStorage();
+  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);
+      }
+    }
+  }
+}
+
diff --git a/core/includes/install.inc b/core/includes/install.inc
index 96e84b3..32c9941 100644
--- a/core/includes/install.inc
+++ b/core/includes/install.inc
@@ -1,7 +1,7 @@
 <?php
 
 use Drupal\Core\Database\Database;
-use Drupal\Core\Config\FileStorage;
+use Drupal\Core\Config\DatabaseStorage;
 
 /**
  * Indicates that a module has not been installed yet.
@@ -376,24 +376,17 @@ function drupal_uninstall_modules($module_list = array(), $uninstall_dependents
     $module_list = array_keys($module_list);
   }
 
+  $storage = new DatabaseStorage();
   foreach ($module_list as $module) {
     // Uninstall the module.
     module_load_install($module);
     module_invoke($module, 'uninstall');
     drupal_uninstall_schema($module);
 
-    // Remove any stray configuration settings.
-    // Get the names of default configurations provided by this module
-    // by scanning its config directory.
-    $module_config_dir = drupal_get_path('module', $module) . '/config';
-    if (is_dir($module_config_dir)) {
-      $files = glob($module_config_dir . '/*.' . FileStorage::getFileExtension());
-      foreach ($files as $file) {
-        $config_name = basename($file, '.' . FileStorage::getFileExtension());
-        $file_storage = new FileStorage($config_name);
-        // Delete the configuration from storage.
-        $file_storage->delete();
-      }
+    // Remove all configuration belonging to the module.
+    $config_names = $storage->getNamesWithPrefix($module . '.');
+    foreach ($config_names as $config_name) {
+      config($config_name)->delete();
     }
 
     watchdog('system', '%module module uninstalled.', array('%module' => $module), WATCHDOG_INFO);
diff --git a/core/includes/module.inc b/core/includes/module.inc
index a71cb18..e15cd95 100644
--- a/core/includes/module.inc
+++ b/core/includes/module.inc
@@ -487,7 +487,7 @@ function module_enable($module_list, $enable_dependencies = TRUE) {
         $versions = drupal_get_schema_versions($module);
         $version = $versions ? max($versions) : SCHEMA_INSTALLED;
 
-        // Copy any default configuration data to the system config directory/
+        // Install default configuration of the module.
         config_install_default_config($module);
 
         // If the module has no current updates, but has some that were
diff --git a/core/includes/update.inc b/core/includes/update.inc
index 49df15b..a1bd480 100644
--- a/core/includes/update.inc
+++ b/core/includes/update.inc
@@ -942,11 +942,10 @@ function update_variables_to_config($config_name, array $variable_map) {
   $module = strtok($config_name, '.');
 
   // Load and set default configuration values.
-  // Throws a FileStorageReadException if there is no default configuration
-  // file, which is required to exist.
-  $file = new FileStorage($config_name);
-  $file->setPath(drupal_get_path('module', $module) . '/config');
-  $default_data = $file->read();
+  // Throws a StorageException if there is no default configuration file, which
+  // is required to exist.
+  $file = new FileStorage(array('directory' => drupal_get_path('module', $module) . '/config'));
+  $default_data = $file->read($config_name);
 
   // Merge any possibly existing original data into default values.
   // Only relevant when being called repetitively on the same config object.
diff --git a/core/lib/Drupal/Core/Config/DrupalConfig.php b/core/lib/Drupal/Core/Config/Config.php
similarity index 69%
rename from core/lib/Drupal/Core/Config/DrupalConfig.php
rename to core/lib/Drupal/Core/Config/Config.php
index f5a9220..4edbc2a 100644
--- a/core/lib/Drupal/Core/Config/DrupalConfig.php
+++ b/core/lib/Drupal/Core/Config/Config.php
@@ -2,20 +2,17 @@
 
 namespace Drupal\Core\Config;
 
-use Drupal\Core\Config\StorageInterface;
-use Drupal\Core\Config\ConfigException;
-
 /**
- * Represents the default configuration storage object.
+ * Defines the default configuration object.
  */
-class DrupalConfig {
+class Config {
 
   /**
-   * The storage engine to save this config object to.
+   * The name of the configuration object.
    *
-   * @var StorageInterface
+   * @var string
    */
-  protected $storage;
+  protected $name;
 
   /**
    * The data of the configuration object.
@@ -25,38 +22,35 @@ class DrupalConfig {
   protected $data = array();
 
   /**
-   * Constructs a DrupalConfig object.
+   * The wrapping storage manager object.
    *
-   * @param StorageInterface $storage
-   *   The storage engine where this config object should be saved.
+   * @var Drupal\Core\Config\StorageManager
+   */
+  protected $storageManager;
+
+  /**
+   * Constructs a configuration object.
    *
-   * @todo $this should really know about $name and make it publicly accessible.
+   * @param Drupal\Core\Config\StorageManager $storageManager
+   *   The wrapping configuration manager object.
    */
-  public function __construct(StorageInterface $storage) {
-    $this->storage = $storage;
-    $this->read();
+  public function __construct(StorageManager $storageManager) {
+    $this->storageManager = $storageManager;
   }
 
   /**
-   * Reads config data from the active store into our object.
+   * Returns the name of this configuration object.
    */
-  public function read() {
-    $data = $this->storage->read();
-    $this->setData($data !== FALSE ? $data : array());
-    return $this;
+  public function getName() {
+    return $this->name;
   }
 
   /**
-   * Checks whether a particular value is overridden.
-   *
-   * @param $key
-   *   @todo
-   *
-   * @return
-   *   @todo
+   * Sets the name of this configuration object.
    */
-  public function isOverridden($key) {
-    return isset($this->_overrides[$key]);
+  public function setName($name) {
+    $this->name = $name;
+    return $this;
   }
 
   /**
@@ -89,7 +83,7 @@ class DrupalConfig {
   public function get($key = '') {
     global $conf;
 
-    $name = $this->storage->getName();
+    $name = $this->getName();
     if (isset($conf[$name])) {
       $merged_data = drupal_array_merge_deep($this->data, $conf[$name]);
     }
@@ -201,13 +195,48 @@ class DrupalConfig {
     else {
       drupal_array_unset_nested_value($this->data, $parts);
     }
+    return $this;
+  }
+
+  /**
+   * Loads configuration data into this object.
+   */
+  public function load() {
+    $this->setData(array());
+    $data = $this->storageManager->selectStorage('read', $this->name)->read($this->name);
+    if ($data !== FALSE) {
+      $this->setData($data);
+    }
+    return $this;
   }
 
   /**
    * Saves the configuration object.
    */
   public function save() {
-    $this->storage->write($this->data);
+    $this->sortByKey($this->data);
+    $this->storageManager->selectStorage('write', $this->name)->write($this->name, $this->data);
+    return $this;
+  }
+
+  /**
+   * Sorts all keys in configuration data.
+   *
+   * Ensures that re-inserted keys appear in the same location as before, in
+   * order to ensure an identical order regardless of storage controller.
+   * A consistent order is important for any storage that allows any kind of
+   * diff operation.
+   *
+   * @param array $data
+   *   An associative array to sort recursively by key name.
+   */
+  public function sortByKey(array &$data) {
+    ksort($data);
+    foreach ($data as &$value) {
+      if (is_array($value)) {
+        $this->sortByKey($value);
+      }
+    }
   }
 
   /**
@@ -215,6 +244,7 @@ class DrupalConfig {
    */
   public function delete() {
     $this->data = array();
-    $this->storage->delete();
+    $this->storageManager->selectStorage('write', $this->name)->delete($this->name);
+    return $this;
   }
 }
diff --git a/core/lib/Drupal/Core/Config/ConfigException.php b/core/lib/Drupal/Core/Config/ConfigException.php
index c60a449..8a81b6e 100644
--- a/core/lib/Drupal/Core/Config/ConfigException.php
+++ b/core/lib/Drupal/Core/Config/ConfigException.php
@@ -1,8 +1,15 @@
 <?php
 
+/**
+ * @file
+ * Definition of Drupal\Core\Config\ConfigException.
+ */
+
 namespace Drupal\Core\Config;
 
+use RuntimeException;
+
 /**
- * @todo
+ * A base exception to the thrown in any configuration system operations.
  */
-class ConfigException extends \Exception {}
+class ConfigException extends RuntimeException {}
diff --git a/core/lib/Drupal/Core/Config/ConfigFactory.php b/core/lib/Drupal/Core/Config/ConfigFactory.php
new file mode 100644
index 0000000..d749281
--- /dev/null
+++ b/core/lib/Drupal/Core/Config/ConfigFactory.php
@@ -0,0 +1,66 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Config\ConfigFactory.
+ */
+
+namespace Drupal\Core\Config;
+
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+
+/**
+ * Defines the configuration object factory.
+ *
+ * The configuration object factory instantiates a configuration object for each
+ * configuration object name that is accessed and returns the configuration
+ * object to callers.
+ *
+ * Each configuration object is wrapped by a configuration manager object, which
+ * is used to determine the storage controller to use for reading and writing
+ * the configuration object data.
+ *
+ * @see Drupal\Core\Config\Config
+ */
+class ConfigFactory {
+  protected $containerClass;
+
+  protected $storageManager;
+
+  public function __construct($container_class, StorageManager $storage_manager) {
+    $this->containerClass = $container_class;
+    $this->storageManager = $storage_manager;
+  }
+
+  /**
+   * Returns a configuration object for a given name.
+   *
+   * @param string $name
+   *   The name of the configuration object to construct.
+   *
+   * @return Drupal\Core\Config\Config
+   *   A configuration object with the given $name.
+   */
+  public function get($name) {
+    // @todo Caching the instantiated objects per name might cut off a fair
+    //   amount of CPU time and memory. Only the data within the configuration
+    //   object changes, so the additional cost of instantiating duplicate
+    //   objects could possibly be avoided. It is not uncommon for a
+    //   configuration object to be retrieved many times during a single
+    //   request; e.g., 'system.performance' alone is retrieved around 10-20
+    //   times within a single page request. Sub-requests via HttpKernel will
+    //   most likely only increase these counts.
+    // @todo Benchmarks were performed with a script that essentially retained
+    //   all instantiated configuration objects in memory until script execution
+    //   ended. A variant of that script called config() within a helper
+    //   function only, which inherently meant that PHP destroyed all
+    //   configuration objects after leaving the function. Consequently,
+    //   benchmark results looked entirely different. Profiling should probably
+    //   redone under more realistic conditions; e.g., actual HTTP requests.
+    // @todo The decrease of CPU time is interesting, since that means that
+    //   ContainerBuilder involves plenty of function calls (which are known to
+    //   be slow in PHP).
+    $config = new $this->containerClass($this->storageManager);
+    return $config->setName($name);
+  }
+}
diff --git a/core/lib/Drupal/Core/Config/DatabaseStorage.php b/core/lib/Drupal/Core/Config/DatabaseStorage.php
index c736245..cb1d925 100644
--- a/core/lib/Drupal/Core/Config/DatabaseStorage.php
+++ b/core/lib/Drupal/Core/Config/DatabaseStorage.php
@@ -2,25 +2,52 @@
 
 namespace Drupal\Core\Config;
 
-use Drupal\Core\Config\StorageBase;
+use Drupal\Core\Config\StorageInterface;
+use Drupal\Core\Database\Database;
 use Exception;
 
 /**
- * Represents an SQL-based configuration storage object.
+ * Defines the Database storage controller.
  */
-class DatabaseStorage extends StorageBase {
+class DatabaseStorage implements StorageInterface {
+
+  /**
+   * Database connection options for this storage controller.
+   *
+   * - target: The connection to use for storage operations.
+   *
+   * @var array
+   */
+  protected $options;
+
+  /**
+   * Implements StorageInterface::__construct().
+   */
+  public function __construct(array $options = array()) {
+    $options += array(
+      'target' => 'default',
+    );
+    $this->options = $options;
+  }
+
+  /**
+   * Returns the database connection to use.
+   */
+  protected function getConnection() {
+    return Database::getConnection($this->options['target']);
+  }
 
   /**
    * Implements StorageInterface::read().
    */
-  public function read() {
+  public function read($name) {
     // There are situations, like in the installer, where we may attempt a
     // read without actually having the database available. In this case,
     // catch the exception and just return an empty array so the caller can
     // handle it if need be.
     $data = array();
     try {
-      $raw = db_query('SELECT data FROM {config} WHERE name = :name', array(':name' => $this->name))->fetchField();
+      $raw = $this->getConnection()->query('SELECT data FROM {config} WHERE name = :name', array(':name' => $name), $this->options)->fetchField();
       if ($raw !== FALSE) {
         $data = $this->decode($raw);
       }
@@ -31,22 +58,22 @@ class DatabaseStorage extends StorageBase {
   }
 
   /**
-   * Implements StorageInterface::writeToActive().
+   * Implements StorageInterface::write().
    */
-  public function writeToActive($data) {
+  public function write($name, array $data) {
     $data = $this->encode($data);
-    return db_merge('config')
-      ->key(array('name' => $this->name))
+    return $this->getConnection()->merge('config', $this->options)
+      ->key(array('name' => $name))
       ->fields(array('data' => $data))
       ->execute();
   }
 
   /**
-   * @todo
+   * Implements StorageInterface::delete().
    */
-  public function deleteFromActive() {
-    db_delete('config')
-      ->condition('name', $this->name)
+  public function delete($name) {
+    $this->getConnection()->delete('config', $this->options)
+      ->condition('name', $name)
       ->execute();
   }
 
@@ -67,7 +94,9 @@ class DatabaseStorage extends StorageBase {
   /**
    * Implements StorageInterface::getNamesWithPrefix().
    */
-  static public function getNamesWithPrefix($prefix = '') {
-    return db_query('SELECT name FROM {config} WHERE name LIKE :name', array(':name' => db_like($prefix) . '%'))->fetchCol();
+  public function getNamesWithPrefix($prefix = '') {
+    return $this->getConnection()->query('SELECT name FROM {config} WHERE name LIKE :name', array(
+      ':name' => db_like($prefix) . '%',
+    ), $this->options)->fetchCol();
   }
 }
diff --git a/core/lib/Drupal/Core/Config/FileStorage.php b/core/lib/Drupal/Core/Config/FileStorage.php
index 2a6d448..bafd099 100644
--- a/core/lib/Drupal/Core/Config/FileStorage.php
+++ b/core/lib/Drupal/Core/Config/FileStorage.php
@@ -2,58 +2,31 @@
 
 namespace Drupal\Core\Config;
 
+use Drupal\Core\Config\StorageInterface;
 use Symfony\Component\Yaml\Yaml;
 
 /**
- * Represents the file storage controller.
- *
- * @todo Implement StorageInterface after removing DrupalConfig methods.
- * @todo Consider to extend StorageBase.
+ * Defines the file storage controller.
  */
-class FileStorage {
+class FileStorage implements StorageInterface {
 
   /**
-   * The name of the configuration object.
+   * Configuration options for this storage controller.
    *
-   * @var string
-   */
-  protected $name;
-
-  /**
-   * The filesystem path containing the configuration object.
+   * - directory: The filesystem path for configuration objects.
    *
-   * @var string
+   * @var array
    */
-  protected $path;
+  protected $options;
 
   /**
    * Implements StorageInterface::__construct().
    */
-  public function __construct($name = NULL) {
-    $this->name = $name;
-  }
-
-  /**
-   * Returns the path containing the configuration file.
-   *
-   * @return string
-   *   The relative path to the configuration object.
-   */
-  public function getPath() {
-    // If the path has not been set yet, retrieve and assign the default path
-    // for configuration files.
-    if (!isset($this->path)) {
-      $this->setPath(config_get_config_directory());
+  public function __construct(array $options = array()) {
+    if (!isset($options['directory'])) {
+      $options['directory'] = config_get_config_directory();
     }
-    return $this->path;
-  }
-
-  /**
-   * Sets the path containing the configuration file.
-   */
-  public function setPath($directory) {
-    $this->path = $directory;
-    return $this;
+    $this->options = $options;
   }
 
   /**
@@ -62,8 +35,8 @@ class FileStorage {
    * @return string
    *   The path to the configuration file.
    */
-  public function getFilePath() {
-    return $this->getPath() . '/' . $this->getName() . '.' . self::getFileExtension();
+  public function getFilePath($name) {
+    return $this->options['directory'] . '/' . $name . '.' . self::getFileExtension();
   }
 
   /**
@@ -82,36 +55,38 @@ class FileStorage {
    * @return bool
    *   TRUE if the configuration file exists, FALSE otherwise.
    */
-  protected function exists() {
-    return file_exists($this->getFilePath());
+  public function exists($name) {
+    return file_exists($this->getFilePath($name));
   }
 
   /**
    * Implements StorageInterface::write().
    *
-   * @throws FileStorageException
+   * @throws StorageException
    */
-  public function write($data) {
+  public function write($name, array $data) {
     $data = $this->encode($data);
-    if (!file_put_contents($this->getFilePath(), $data)) {
-      throw new FileStorageException('Failed to write configuration file: ' . $this->getFilePath());
+    if (!file_put_contents($this->getFilePath($name), $data)) {
+      throw new StorageException('Failed to write configuration file: ' . $this->getFilePath($name));
     }
+    return $this;
   }
 
   /**
    * Implements StorageInterface::read().
    *
-   * @throws FileStorageReadException
+   * @throws StorageException
    */
-  public function read() {
-    if (!$this->exists()) {
-      throw new FileStorageReadException("Configuration file '$this->name' does not exist.");
+  public function read($name) {
+    // @todo DatabaseStorage does not throw an exception if $name does not exist.
+    if (!$this->exists($name)) {
+      throw new StorageException("Configuration file '$name' does not exist.");
     }
 
-    $data = file_get_contents($this->getFilePath());
+    $data = file_get_contents($this->getFilePath($name));
     $data = $this->decode($data);
     if ($data === FALSE) {
-      throw new FileStorageReadException("Failed to decode configuration file '$this->name'.");
+      throw new StorageException("Failed to decode configuration file '$name'.");
     }
     return $data;
   }
@@ -119,9 +94,9 @@ class FileStorage {
   /**
    * Deletes a configuration file.
    */
-  public function delete() {
-    // Needs error handling and etc.
-    @drupal_unlink($this->getFilePath());
+  public function delete($name) {
+    // @todo Error handling.
+    return @drupal_unlink($this->getFilePath($name));
   }
 
   /**
@@ -144,28 +119,13 @@ class FileStorage {
   }
 
   /**
-   * Implements StorageInterface::getName().
-   */
-  public function getName() {
-    return $this->name;
-  }
-
-  /**
-   * Implements StorageInterface::setName().
-   */
-  public function setName($name) {
-    $this->name = $name;
-  }
-
-  /**
    * Implements StorageInterface::getNamesWithPrefix().
    */
-  public static function getNamesWithPrefix($prefix = '') {
-    // @todo Use $this->getPath() to allow for contextual search of files in
-    //   custom paths.
-    $files = glob(config_get_config_directory() . '/' . $prefix . '*.' . FileStorage::getFileExtension());
-    $clean_name = function ($value) {
-      return basename($value, '.' . FileStorage::getFileExtension());
+  public function getNamesWithPrefix($prefix = '') {
+    $extension = '.' . self::getFileExtension();
+    $files = glob($this->options['directory'] . '/' . $prefix . '*' . $extension);
+    $clean_name = function ($value) use ($extension) {
+      return basename($value, $extension);
     };
     return array_map($clean_name, $files);
   }
diff --git a/core/lib/Drupal/Core/Config/FileStorageException.php b/core/lib/Drupal/Core/Config/FileStorageException.php
deleted file mode 100644
index bf3ae5f..0000000
--- a/core/lib/Drupal/Core/Config/FileStorageException.php
+++ /dev/null
@@ -1,10 +0,0 @@
-<?php
-
-namespace Drupal\Core\Config;
-
-use Drupal\Core\Config\ConfigException;
-
-/**
- * @todo
- */
-class FileStorageException extends ConfigException {}
diff --git a/core/lib/Drupal/Core/Config/FileStorageReadException.php b/core/lib/Drupal/Core/Config/FileStorageReadException.php
deleted file mode 100644
index d613666..0000000
--- a/core/lib/Drupal/Core/Config/FileStorageReadException.php
+++ /dev/null
@@ -1,10 +0,0 @@
-<?php
-
-namespace Drupal\Core\Config;
-
-use Drupal\Core\Config\FileStorageException;
-
-/**
- * @todo
- */
-class FileStorageReadException extends FileStorageException {}
diff --git a/core/lib/Drupal/Core/Config/StorageBase.php b/core/lib/Drupal/Core/Config/StorageBase.php
deleted file mode 100644
index b03ff27..0000000
--- a/core/lib/Drupal/Core/Config/StorageBase.php
+++ /dev/null
@@ -1,121 +0,0 @@
-<?php
-
-namespace Drupal\Core\Config;
-
-use Drupal\Core\Config\StorageInterface;
-use Drupal\Core\Config\FileStorage;
-
-/**
- * Base class for configuration storage controllers.
- */
-abstract class StorageBase implements StorageInterface {
-
-  /**
-   * The name of the configuration object.
-   *
-   * @var string
-   */
-  protected $name;
-
-  /**
-   * The local file object to read from and write to.
-   *
-   * @var Drupal\Core\Config\FileStorage
-   */
-  protected $fileStorage;
-
-  /**
-   * Implements StorageInterface::__construct().
-   */
-  function __construct($name = NULL) {
-    $this->name = $name;
-  }
-
-  /**
-   * Instantiates a new file storage object or returns the existing one.
-   *
-   * @return Drupal\Core\Config\FileStorage
-   *   The file object for this configuration object.
-   */
-  protected function fileStorage() {
-    if (!isset($this->fileStorage)) {
-      $this->fileStorage = new FileStorage($this->name);
-    }
-    return $this->fileStorage;
-  }
-
-  /**
-   * Implements StorageInterface::copyToFile().
-   */
-  public function copyToFile() {
-    return $this->writeToFile($this->read());
-  }
-
-  /**
-   * Implements StorageInterface::deleteFile().
-   */
-  public function deleteFile() {
-    return $this->fileStorage()->delete();
-  }
-
-  /**
-   * Implements StorageInterface::copyFromFile().
-   */
-  public function copyFromFile() {
-    return $this->writeToActive($this->readFromFile());
-  }
-
-  /**
-   * @todo
-   *
-   * @return
-   *   @todo
-   */
-  public function readFromFile() {
-    return $this->fileStorage()->read($this->name);
-  }
-
-  /**
-   * Implements StorageInterface::isOutOfSync().
-   */
-  public function isOutOfSync() {
-    return $this->read() !== $this->readFromFile();
-  }
-
-  /**
-   * Implements StorageInterface::write().
-   */
-  public function write($data) {
-    $this->writeToActive($data);
-    $this->writeToFile($data);
-  }
-
-  /**
-   * Implements StorageInterface::writeToFile().
-   */
-  public function writeToFile($data) {
-    return $this->fileStorage()->write($data);
-  }
-
-  /**
-   * Implements StorageInterface::delete().
-   */
-  public function delete() {
-    $this->deleteFromActive();
-    $this->deleteFile();
-  }
-
-  /**
-   * Implements StorageInterface::getName().
-   */
-  public function getName() {
-    return $this->name;
-  }
-
-  /**
-   * Implements StorageInterface::setName().
-   */
-  public function setName($name) {
-    $this->name = $name;
-  }
-}
diff --git a/core/lib/Drupal/Core/Config/StorageException.php b/core/lib/Drupal/Core/Config/StorageException.php
new file mode 100644
index 0000000..8fddd17
--- /dev/null
+++ b/core/lib/Drupal/Core/Config/StorageException.php
@@ -0,0 +1,15 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Config\StorageException.
+ */
+
+namespace Drupal\Core\Config;
+
+use Drupal\Core\Config\ConfigException;
+
+/**
+ * An exception to be thrown in case of storage controller operation errors.
+ */
+class StorageException extends ConfigException {}
diff --git a/core/lib/Drupal/Core/Config/StorageInterface.php b/core/lib/Drupal/Core/Config/StorageInterface.php
index 43141a5..6ad1c11 100644
--- a/core/lib/Drupal/Core/Config/StorageInterface.php
+++ b/core/lib/Drupal/Core/Config/StorageInterface.php
@@ -7,74 +7,43 @@ namespace Drupal\Core\Config;
  *
  * Classes implementing this interface allow reading and writing configuration
  * data from and to the storage.
- *
- * @todo Remove all active/file methods. They belong onto DrupalConfig only.
  */
 interface StorageInterface {
 
   /**
-   * Constructs a storage manipulation class.
+   * Constructs the storage controller.
    *
-   * @param string $name
-   *   (optional) The name of a configuration object to load.
-   */
-  function __construct($name = NULL);
-
-  /**
-   * Reads the configuration data from the storage.
-   */
-  function read();
-
-  /**
-   * Copies the configuration data from the storage into a file.
+   * @param array $options
+   *   An associative array containing configuration options specific to the
+   *   storage controller.
    */
-  function copyToFile();
+  public function __construct(array $options = array());
 
   /**
-   * Copies the configuration data from the file into the storage.
-   */
-  function copyFromFile();
-
-  /**
-   * Deletes the configuration data file.
-   */
-  function deleteFile();
-
-  /**
-   * Checks whether the file and the storage is in sync.
+   * Reads configuration data from the storage.
    *
-   * @return
-   *   TRUE if the file and the storage contains the same data, FALSE
-   *   if not.
+   * @param string $name
+   *   The name of a configuration object to load.
    */
-  function isOutOfSync();
+  public function read($name);
 
   /**
-   * Writes the configuration data into the active storage and the file.
+   * Writes configuration data to the storage.
    *
-   * @param $data
+   * @param string $name
+   *   The name of a configuration object to save.
+   * @param array $data
    *   The configuration data to write.
    */
-  function write($data);
-
-  /**
-   * Writes the configuration data into the active storage but not the file.
-   *
-   * Use this function if you need to make temporary changes to your
-   * configuration.
-   *
-   * @param $data
-   *   The configuration data to write into active storage.
-   */
-  function writeToActive($data);
+  public function write($name, array $data);
 
   /**
-   * Writes the configuration data into the file.
+   * Deletes a configuration object from the storage.
    *
-   * @param $data
-   *   The configuration data to write into the file.
+   * @param string $name
+   *   The name of a configuration object to delete.
    */
-  function writeToFile($data);
+  public function delete($name);
 
   /**
    * Encodes configuration data into the storage-specific format.
@@ -105,16 +74,6 @@ interface StorageInterface {
   public static function decode($raw);
 
   /**
-   * Gets the name of this object.
-   */
-  public function getName();
-
-  /**
-   * Sets the name of this object.
-   */
-  public function setName($name);
-
-  /**
    * Gets configuration object names starting with a given prefix.
    *
    * Given the following configuration objects:
@@ -131,5 +90,5 @@ interface StorageInterface {
    * @return array
    *   An array containing matching configuration object names.
    */
-  static function getNamesWithPrefix($prefix = '');
+  public function getNamesWithPrefix($prefix = '');
 }
diff --git a/core/lib/Drupal/Core/Config/StorageManager.php b/core/lib/Drupal/Core/Config/StorageManager.php
new file mode 100644
index 0000000..82afe01
--- /dev/null
+++ b/core/lib/Drupal/Core/Config/StorageManager.php
@@ -0,0 +1,98 @@
+<?php
+
+namespace Drupal\Core\Config;
+
+/**
+ * Manages configuration storage controllers.
+ *
+ * A high-level storage manager that determines which storage out of multiple
+ * is configured and allowed to handle a particular configuration object,
+ * depending on the read/write operation being performed.
+ *
+ * The information about available storage controllers and their configuration
+ * options is passed once into the constructor and normally should not change
+ * within a single request or context. Special use-cases, such as import and
+ * export operations, should instantiate a custom configuration manager tailored
+ * to their application needs.
+ *
+ * The configuration manager instantiates storage controllers on demand, and
+ * only once per storage.
+ *
+ * @see Drupal\Core\Config\StorageInterface
+ */
+class StorageManager {
+
+  /**
+   * Information about available storage controllers.
+   *
+   * @var array
+   */
+  protected $storageInfo;
+
+  /**
+   * Instantiated storage controller objects.
+   *
+   * @see Drupal\Core\Config\StorageInterface
+   *
+   * @var array
+   */
+  protected $storageInstances;
+
+  /**
+   * Constructs the storage manager object.
+   *
+   * @param array $storage_info
+   *   An associative array defining the storage controllers to use and any
+   *   required configuration for them; e.g.:
+   *   @code
+   *   array(
+   *     'Drupal\Core\Config\DatabaseStorage' => array(
+   *       'target' => 'default',
+   *       'read' => TRUE,
+   *       'write' => TRUE,
+   *     ),
+   *     'Drupal\Core\Config\FileStorage' => array(
+   *       'directory' => 'sites/default/files/config',
+   *       'read' => TRUE,
+   *       'write' => FALSE,
+   *     ),
+   *   )
+   *   @endcode
+   */
+  public function __construct(array $storage_info) {
+    $this->storageInfo = $storage_info;
+  }
+
+  /**
+   * Returns a storage controller to use for a given operation.
+   *
+   * Handles the core functionality of the configuration manager by determining
+   * which storage can handle a particular configuration object, depending on
+   * the operation being performed.
+   *
+   * @param string $access_operation
+   *   The operation access level; either 'read' or 'write'. Use 'write' both
+   *   for saving and deleting configuration.
+   * @param string $name
+   *   The name of the configuration object that is operated on.
+   */
+  public function selectStorage($access_operation, $name) {
+    // Determine the appropriate storage controller to use.
+    // Take the first defined storage that allows $op.
+    foreach ($this->storageInfo as $class => $storage_config) {
+      if (!empty($storage_config[$access_operation])) {
+        $storage_class = $class;
+        break;
+      }
+    }
+    if (!isset($storage_class)) {
+      throw new ConfigException("Failed to find storage controller that allows $access_operation access for $name.");
+    }
+
+    // Instantiate a new storage controller object, if there is none yet.
+    if (!isset($this->storageInstances[$storage_class])) {
+      $this->storageInstances[$storage_class] = new $storage_class($this->storageInfo[$storage_class]);
+    }
+    return $this->storageInstances[$storage_class];
+  }
+}
diff --git a/core/lib/Drupal/Core/DependencyInjection/ContainerBuilder.php b/core/lib/Drupal/Core/DependencyInjection/ContainerBuilder.php
index aa73ace..706960d 100644
--- a/core/lib/Drupal/Core/DependencyInjection/ContainerBuilder.php
+++ b/core/lib/Drupal/Core/DependencyInjection/ContainerBuilder.php
@@ -8,6 +8,8 @@
 namespace Drupal\Core\DependencyInjection;
 
 use Symfony\Component\DependencyInjection\ContainerBuilder as BaseContainerBuilder;
+use Symfony\Component\DependencyInjection\Reference;
+
 
 /**
  * Drupal's dependency injection container.
@@ -27,5 +29,29 @@ class ContainerBuilder extends BaseContainerBuilder {
 
     // Register the default language content.
     $this->register(LANGUAGE_TYPE_CONTENT, 'Drupal\\Core\\Language\\Language');
+
+    // Register configuration system manager.
+    $this->setParameter('config.storage.manager', 'Drupal\Core\Config\StorageManager');
+    $this->setParameter('config.storage.info', array(
+      'Drupal\Core\Config\DatabaseStorage' => array(
+        'target' => 'default',
+        'read' => TRUE,
+        'write' => TRUE,
+      ),
+      'Drupal\Core\Config\FileStorage' => array(
+        'directory' => config_get_config_directory(),
+        'read' => TRUE,
+        'write' => FALSE,
+      ),
+    ));
+    $this->register('config.storage.manager', '%config.storage.manager%')
+      ->addArgument('%config.storage.info%');
+
+    // Register configuration system.
+    $this->setParameter('config.factory', 'Drupal\Core\Config\ConfigFactory');
+    $this->setParameter('config.container', 'Drupal\Core\Config\Config');
+    $this->register('config.factory', '%config.factory%')
+      ->addArgument('%config.container%')
+      ->addArgument(new Reference('config.storage.manager'));
   }
 }
diff --git a/core/modules/config/config.admin.inc b/core/modules/config/config.admin.inc
new file mode 100644
index 0000000..6f77bf2
--- /dev/null
+++ b/core/modules/config/config.admin.inc
@@ -0,0 +1,62 @@
+<?php
+
+/**
+ * @file
+ * Admin page callbacks for the config module.
+ */
+
+/**
+ * Form constructor for configuration import form.
+ *
+ * @see config_admin_import_form_submit()
+ */
+function config_admin_import_form($form, &$form_state) {
+  $config_changes = config_import_get_changes();
+
+  if (empty($config_changes)) {
+    $form['no_changes'] = array(
+      '#markup' => t('There are no configuration changes.'),
+    );
+    return $form;
+  }
+
+  foreach ($config_changes as $config_change_type => $config_files) {
+    if (empty($config_files)) {
+      continue;
+    }
+    $form[$config_change_type] = array(
+      '#type' => 'fieldset',
+      '#title' => $config_change_type . ' (' . count($config_files) . ')',
+      '#collapsible' => TRUE,
+    );
+    $form[$config_change_type]['config_files'] = array(
+      '#theme' => 'table',
+      '#header' => array('Name'),
+    );
+    foreach ($config_files as $config_file) {
+      $form[$config_change_type]['config_files']['#rows'][] = array($config_file);
+    }
+  }
+  $form['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Import'),
+  );
+  return $form;
+}
+
+/**
+ * Form submission handler for config_admin_import_form().
+ */
+function config_admin_import_form_submit($form, &$form_state) {
+  if (config_import()) {
+    drupal_set_message(t('The configuration was imported successfully.'));
+  }
+  else {
+    // Another request may be synchronizing configuration already. Wait for it
+    // to complete before returning the error, so already synchronized changes
+    // do not appear again.
+    lock_wait(__FUNCTION__);
+    drupal_set_message(t('The import failed due to an error. Any errors have been logged.'), 'error');
+  }
+}
+
diff --git a/core/modules/config/config.api.php b/core/modules/config/config.api.php
new file mode 100644
index 0000000..8f95d32
--- /dev/null
+++ b/core/modules/config/config.api.php
@@ -0,0 +1,56 @@
+<?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 hook is invoked when configuration is synchronized between storages and
+ * allows a module to take over the synchronization of configuration data.
+ *
+ * Modules should implement this hook if they manage higher-level 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\DrupalConfig $new_config
+ *   A configuration object containing the new configuration data.
+ * @param Drupal\Core\Config\DrupalConfig $old_config
+ *   A configuration object containing the old configuration data.
+ */
+function hook_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') {
+    $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);
+  }
+}
+
diff --git a/core/modules/config/config.module b/core/modules/config/config.module
index b3d9bbc..3d4fcfe 100644
--- a/core/modules/config/config.module
+++ b/core/modules/config/config.module
@@ -1 +1,33 @@
 <?php
+
+/**
+ * @file
+ * Allows site administrators to modify configuration.
+ */
+
+/**
+ * Implements hook_permission().
+ */
+function config_permission() {
+  $permissions['import configuration'] = array(
+    'title' => t('Import configuration'),
+    'restrict access' => TRUE,
+  );
+  return $permissions;
+}
+
+/**
+ * Implements hook_menu().
+ */
+function config_menu() {
+  $items['admin/config/development/import'] = array(
+    'title' => 'Import configuration',
+    'description' => 'Import and synchronize configuration changes.',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('config_admin_import_form'),
+    'access arguments' => array('import configuration'),
+    'file' => 'config.admin.inc',
+  );
+  return $items;
+}
+
diff --git a/core/modules/config/config_test/config/config_test.delete.yml b/core/modules/config/config_test/config/config_test.delete.yml
new file mode 100644
index 0000000..b8ccb67
--- /dev/null
+++ b/core/modules/config/config_test/config/config_test.delete.yml
@@ -0,0 +1 @@
+delete_me: bar
diff --git a/core/modules/config/config_test/config/config_test.dynamic.default.yml b/core/modules/config/config_test/config/config_test.dynamic.default.yml
new file mode 100644
index 0000000..d285439
--- /dev/null
+++ b/core/modules/config/config_test/config/config_test.dynamic.default.yml
@@ -0,0 +1,2 @@
+id: default
+name: Default
diff --git a/core/modules/config/config_test/config/config_test.system.yml b/core/modules/config/config_test/config/config_test.system.yml
new file mode 100644
index 0000000..20e9ff3
--- /dev/null
+++ b/core/modules/config/config_test/config/config_test.system.yml
@@ -0,0 +1 @@
+foo: bar
diff --git a/core/modules/config/config_test/config_test.info b/core/modules/config/config_test/config_test.info
new file mode 100644
index 0000000..8735450
--- /dev/null
+++ b/core/modules/config/config_test/config_test.info
@@ -0,0 +1,6 @@
+name = Configuration test module
+package = Core
+version = VERSION
+core = 8.x
+dependencies[] = config
+hidden = TRUE
diff --git a/core/modules/config/config_test/config_test.module b/core/modules/config/config_test/config_test.module
new file mode 100644
index 0000000..7572224
--- /dev/null
+++ b/core/modules/config/config_test/config_test.module
@@ -0,0 +1,240 @@
+<?php
+
+use Drupal\Core\Config\ConfigException;
+use Drupal\config_test\ConfigTest;
+
+/**
+ * Implements hook_config_import().
+ */
+function config_test_config_import($op, $name, $new_config, $old_config) {
+  // Set a global value we can check in test code.
+  $GLOBALS['hook_config_import'] = __FUNCTION__;
+
+  // 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. Good idea.
+    //   But squeezing that into a "delete" operation is the worst idea ever.
+    //   Regardless of Image module insanity, add a 'replaced' stack to
+    //   config_import()? And how can that work? If an 'old_ID' key would be a
+    //   standard, wouldn't this belong into 'changed' instead?
+    $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;
+}
+
+/**
+ * Implements hook_menu().
+ */
+function config_test_menu() {
+  $items['admin/structure/config_test'] = array(
+    'title' => 'Test configuration',
+    'page callback' => 'config_test_list_page',
+    'access callback' => TRUE,
+  );
+  $items['admin/structure/config_test/add'] = array(
+    'title' => 'Add test configuration',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('config_test_form'),
+    'access callback' => TRUE,
+    'type' => MENU_LOCAL_ACTION,
+  );
+  $items['admin/structure/config_test/manage/%config_test'] = array(
+    'title' => 'Edit test configuration',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('config_test_form', 4),
+    'access callback' => TRUE,
+  );
+  $items['admin/structure/config_test/manage/%config_test/edit'] = array(
+    'title' => 'Edit',
+    'type' => MENU_DEFAULT_LOCAL_TASK,
+    'weight' => -10,
+  );
+  $items['admin/structure/config_test/manage/%config_test/delete'] = array(
+    'title' => 'Delete',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('config_test_delete_form', 4),
+    'access callback' => TRUE,
+    'type' => MENU_LOCAL_TASK,
+  );
+  return $items;
+}
+
+/**
+ * Loads a ConfigTest object.
+ *
+ * @param string $id
+ *   The ID of the ConfigTest object to load.
+ */
+function config_test_load($id) {
+  $config = config('config_test.dynamic.' . $id);
+  // @todo Requires a more reliable + generic method to check for whether the
+  //   configuration object exists.
+  if ($config->get('id') === NULL) {
+    return FALSE;
+  }
+  return new ConfigTest($config);
+}
+
+/**
+ * Saves a ConfigTest object.
+ *
+ * @param Drupal\config_test\ConfigTest $config_test
+ *   The ConfigTest object to save.
+ */
+function config_test_save(ConfigTest $config_test) {
+  return $config_test->save();
+}
+
+/**
+ * Deletes a ConfigTest object.
+ *
+ * @param string $id
+ *   The ID of the ConfigTest object to delete.
+ */
+function config_test_delete($id) {
+  $config = config('config_test.dynamic.' . $id);
+  $config_test = new ConfigTest($config);
+  return $config_test->delete();
+}
+
+/**
+ * Page callback; Lists available ConfigTest objects.
+ */
+function config_test_list_page() {
+  $config_names = config_get_storage_names_with_prefix('config_test.dynamic.');
+  $rows = array();
+  foreach ($config_names as $config_name) {
+    $config_test = new ConfigTest(config($config_name));
+    $row = array();
+    $row['name']['data'] = array(
+      '#type' => 'link',
+      '#title' => $config_test->getLabel(),
+      '#href' => $config_test->getUri(),
+    );
+    $row['delete']['data'] = array(
+      '#type' => 'link',
+      '#title' => t('Delete'),
+      '#href' => $config_test->getUri() . '/delete',
+    );
+    $rows[] = $row;
+  }
+  $build = array(
+    '#theme' => 'table',
+    '#header' => array('Name', 'Operations'),
+    '#rows' => $rows,
+    '#empty' => format_string('No test configuration defined. <a href="@add-url">Add some</a>', array(
+      '@add-url' => url('admin/structure/config_test/add'),
+    )),
+  );
+  return $build;
+}
+
+/**
+ * Form constructor to add or edit a ConfigTest object.
+ *
+ * @param Drupal\config_test\ConfigTest $config_test
+ *   (optional) An existing ConfigTest object to edit. If omitted, the form
+ *   creates a new ConfigTest.
+ */
+function config_test_form($form, &$form_state, ConfigTest $config_test = NULL) {
+  if (!isset($config_test)) {
+    $config_test = new ConfigTest(config(NULL));
+  }
+  $form_state['config_test'] = $config_test;
+
+  $form['name'] = array(
+    '#type' => 'textfield',
+    '#title' => 'Label',
+    '#default_value' => $config_test->getLabel(),
+    '#required' => TRUE,
+  );
+  $form['id'] = array(
+    '#type' => 'machine_name',
+    '#default_value' => $config_test->getId(),
+    '#required' => TRUE,
+    '#machine_name' => array(
+      'exists' => 'config_test_load',
+    ),
+  );
+  $form['style'] = array(
+    '#type' => 'select',
+    '#title' => 'Image style',
+    '#options' => array(),
+    '#default_value' => $config_test->get('style'),
+    '#access' => FALSE,
+  );
+  if (module_exists('image')) {
+    $form['style']['#access'] = TRUE;
+    $form['style']['#options'] = image_style_options();
+  }
+
+  $form['actions'] = array('#type' => 'actions');
+  $form['actions']['submit'] = array('#type' => 'submit', '#value' => 'Save');
+
+  return $form;
+}
+
+/**
+ * Form submission handler for config_test_form().
+ */
+function config_test_form_submit($form, &$form_state) {
+  form_state_values_clean($form_state);
+
+  $config_test = $form_state['config_test'];
+
+  foreach ($form_state['values'] as $key => $value) {
+    $config_test->set($key, $value);
+  }
+  $config_test->save();
+
+  if (!empty($config_test->original)) {
+    drupal_set_message(format_string('%label configuration has been updated.', array('%label' => $config_test->getLabel())));
+  }
+  else {
+    drupal_set_message(format_string('%label configuration has been created.', array('%label' => $config_test->getLabel())));
+  }
+
+  $form_state['redirect'] = 'admin/structure/config_test';
+}
+
+/**
+ * Form constructor to delete a ConfigTest object.
+ *
+ * @param Drupal\config_test\ConfigTest $config_test
+ *   The ConfigTest object to delete.
+ */
+function config_test_delete_form($form, &$form_state, ConfigTest $config_test) {
+  $form_state['config_test'] = $config_test;
+
+  $form['id'] = array('#type' => 'value', '#value' => $config_test->getId());
+  return confirm_form($form,
+    format_string('Are you sure you want to delete %label', array('%label' => $config_test->getLabel())),
+    'admin/structure/config_test',
+    NULL,
+    'Delete'
+  );
+}
+
+/**
+ * Form submission handler for config_test_delete_form().
+ */
+function config_test_delete_form_submit($form, &$form_state) {
+  $form_state['config_test']->delete();
+  $form_state['redirect'] = 'admin/structure/config_test';
+}
diff --git a/core/modules/config/config_test/lib/Drupal/config_test/ConfigTest.php b/core/modules/config/config_test/lib/Drupal/config_test/ConfigTest.php
new file mode 100644
index 0000000..2bb25c7
--- /dev/null
+++ b/core/modules/config/config_test/lib/Drupal/config_test/ConfigTest.php
@@ -0,0 +1,178 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\config_test\ConfigTest.
+ */
+
+namespace Drupal\config_test;
+
+/**
+ * Defines the ConfigTest configuration thingie.
+ *
+ * @todo At minimum, introduce a consistent interface for configurable thingies.
+ * @todo Consider to introduce a ConfigObjectBase for all configurable thingies.
+ */
+class ConfigTest {
+  /**
+   * The configuration object.
+   *
+   * @var Drupal\Core\Config\ConfigObject
+   */
+  protected $config;
+
+  /**
+   * The key of the thingie's ID (machine name).
+   *
+   * @var string
+   */
+  public $idKey = 'id';
+
+  /**
+   * The key of the thingie's label.
+   *
+   * @var string
+   */
+  public $labelKey = 'name';
+
+  /**
+   * The thingie's original ID, if any.
+   *
+   * @var string|null
+   */
+  public $originalId;
+
+  /**
+   * The original configuration object, if any, upon update.
+   *
+   * @var Drupal\Core\Config\ConfigObject
+   */
+  public $original;
+
+  // -- Custom properties start --
+
+  /**
+   * The image style to use.
+   *
+   * @var string
+   */
+  public $style;
+
+  // -- Custom properties end --
+
+  /**
+   * Constructs a new ConfigTest thingie.
+   */
+  public function __construct($config) {
+    $this->load($config);
+  }
+
+  /**
+   * Implements Drupal\Core\Config\ConfigObjectInterface::getConfigPrefix().
+   */
+  public function getConfigPrefix() {
+    return 'config_test.dynamic';
+  }
+
+  /**
+   * Implements ConfigObjectInterface::getName().
+   */
+  public function getConfigName() {
+    return $this->getConfigPrefix() . '.' . $this->getId;
+  }
+
+  /**
+   * Implements ConfigObjectInterface::getId().
+   */
+  public function getId() {
+    return $this->config->get($this->idKey);
+  }
+
+  /**
+   * Implements ConfigObjectInterface::isNew().
+   */
+  public function isNew() {
+    return isset($this->originalId);
+  }
+
+  /**
+   * Implements ConfigObjectInterface::getLabel().
+   */
+  public function getLabel() {
+    return $this->config->get($this->labelKey);
+  }
+
+  /**
+   * Implements ConfigObjectInterface::getUri().
+   */
+  public function getUri() {
+    // @todo Check whether this makes sense.
+    return 'admin/structure/config_test/manage/' . $this->getId();
+  }
+
+  /**
+   * Implements ConfigObjectInterface::get().
+   */
+  public function get($property_name, $langcode = NULL) {
+    return $this->config->get($property_name);
+  }
+
+  /**
+   * Implements ConfigObjectInterface::set().
+   */
+  public function set($property_name, $value, $langcode = NULL) {
+    return $this->config->set($property_name, $value);
+  }
+
+  /**
+   * Implements ConfigObjectInterface::setOriginal().
+   */
+  public function setOriginal($config) {
+    $this->original = $config;
+    $this->originalId = $config->get($this->idKey);
+    return $this;
+  }
+
+  /**
+   * Implements ConfigObjectInterface::load().
+   */
+  public function load($config) {
+    $this->config = $config;
+    $this->originalId = $config->get($this->idKey);
+    return $this;
+  }
+
+  /**
+   * Implements ConfigObjectInterface::save().
+   */
+  public function save() {
+    // Provide the original configuration in $config->original, if any.
+    if (isset($this->originalId)) {
+      $original_config = config($this->getConfigPrefix() . '.' . $this->originalId);
+      $this->setOriginal(new $this($original_config));
+
+      // Delete the original configuration, if it was renamed.
+      if ($this->originalId !== $this->getId()) {
+        // Configuration data is emptied out upon delete, so back it up and
+        // re-inject it. Delete the old configuration data directly; hooks will
+        // get and will be able to react to the data in $this->original.
+        $original_data = $original_config->get();
+        $original_config->delete();
+        $original_config->setData($original_data);
+      }
+    }
+
+    // Save the new configuration.
+    $this->config->setName($this->getConfigPrefix() . '.' . $this->getId());
+    $this->config->save();
+
+    return $this;
+  }
+
+  /**
+   * Implements ConfigObjectInterface::delete().
+   */
+  public function delete() {
+    $this->config->delete();
+  }
+}
diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigCRUDTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigCRUDTest.php
new file mode 100644
index 0000000..aeca024
--- /dev/null
+++ b/core/modules/config/lib/Drupal/config/Tests/ConfigCRUDTest.php
@@ -0,0 +1,106 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\config\Tests\ConfigCRUDTest.
+ */
+
+namespace Drupal\config\Tests;
+
+use Drupal\Core\Config\DatabaseStorage;
+use Drupal\simpletest\WebTestBase;
+
+/**
+ * Tests CRUD operations on configuration objects.
+ */
+class ConfigCRUDTest extends WebTestBase {
+  public static function getInfo() {
+    return array(
+      'name' => 'CRUD operations',
+      'description' => 'Tests CRUD operations on configuration objects.',
+      'group' => 'Configuration',
+    );
+  }
+
+  /**
+   * Tests CRUD operations.
+   */
+  function testCRUD() {
+    $storage = new DatabaseStorage();
+    $name = 'config_test.crud';
+
+    // Create a new configuration object.
+    $config = config($name);
+    $config->set('value', 'initial');
+    $config->save();
+
+    // Verify the active store contains the saved value.
+    $actual_data = $storage->read($name);
+    $this->assertIdentical($actual_data, array('value' => 'initial'));
+
+    // Update the configuration object instance.
+    $config->set('value', 'instance-update');
+    $config->save();
+
+    // Verify the active store contains the updated value.
+    $actual_data = $storage->read($name);
+    $this->assertIdentical($actual_data, array('value' => 'instance-update'));
+
+    // Verify a call to config() immediately returns the updated value.
+    $new_config = config($name);
+    $this->assertIdentical($new_config->get(), $config->get());
+
+    // Delete the configuration object.
+    $config->delete();
+
+    // Verify the configuration object is empty.
+    $this->assertIdentical($config->get(), array());
+
+    // Verify the active store contains no value.
+    $actual_data = $storage->read($name);
+    $this->assertIdentical($actual_data, array());
+
+    // Verify config() returns no data.
+    $new_config = config($name);
+    $this->assertIdentical($new_config->get(), $config->get());
+
+    // Re-create the configuration object.
+    $config->set('value', 're-created');
+    $config->save();
+
+    // Verify the active store contains the updated value.
+    $actual_data = $storage->read($name);
+    $this->assertIdentical($actual_data, array('value' => 're-created'));
+
+    // Verify a call to config() immediately returns the updated value.
+    $new_config = config($name);
+    $this->assertIdentical($new_config->get(), $config->get());
+  }
+
+  /**
+   * Tests Drupal\Core\Config\Config::sortByKey().
+   */
+  function testDataKeySort() {
+    $config = config('config_test.keysort');
+    $config->set('new', 'Value to be replaced');
+    $config->set('static', 'static');
+    $config->save();
+    // Clone this Config, so this test does not rely on any particular
+    // architecture.
+    $config = clone $config;
+
+    // Load the configuration data into a new object.
+    $new_config = config('config_test.keysort');
+    // Clear the 'new' key that came first.
+    $new_config->clear('new');
+    // Add a new 'new' key and save.
+    $new_config->set('new', 'Value to be replaced');
+    $new_config->save();
+
+    // Verify that the data of both objects is in the identical order.
+    // assertIdentical() is the required essence of this test; it performs a
+    // strict comparison, which means that keys and values must be identical and
+    // their order must be identical.
+    $this->assertIdentical($new_config->get(), $config->get());
+  }
+}
diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigConfigurableTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigConfigurableTest.php
new file mode 100644
index 0000000..68df5f1
--- /dev/null
+++ b/core/modules/config/lib/Drupal/config/Tests/ConfigConfigurableTest.php
@@ -0,0 +1,80 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\config\Tests\ConfigConfigurableTest.
+ */
+
+namespace Drupal\config\Tests;
+
+use Drupal\simpletest\WebTestBase;
+
+/**
+ * Tests configurable configuration.
+ */
+class ConfigConfigurableTest extends WebTestBase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Configurable configuration',
+      'description' => 'Tests configurable configuration.',
+      'group' => 'Configuration',
+    );
+  }
+
+  function setUp() {
+    parent::setUp(array('config_test'));
+  }
+
+  /**
+   * Tests basic CRUD operations through the UI.
+   */
+  function testCRUD() {
+    // Create a thingie.
+    $id = 'thingie';
+    $edit = array(
+      'id' => $id,
+      'name' => 'Thingie',
+    );
+    $this->drupalPost('admin/structure/config_test/add', $edit, 'Save');
+    $this->assertResponse(200);
+    $this->assertText('Thingie');
+
+    // Update the thingie.
+    $this->assertLinkByHref('admin/structure/config_test/manage/' . $id);
+    $edit = array(
+      'name' => 'Thongie',
+    );
+    $this->drupalPost('admin/structure/config_test/manage/' . $id, $edit, 'Save');
+    $this->assertResponse(200);
+    $this->assertNoText('Thingie');
+    $this->assertText('Thongie');
+
+    // Delete the thingie.
+    $this->assertLinkByHref('admin/structure/config_test/manage/' . $id . '/delete');
+    $this->drupalPost('admin/structure/config_test/manage/' . $id . '/delete', array(), 'Delete');
+    $this->assertResponse(200);
+    $this->assertNoText('Thingie');
+    $this->assertNoText('Thongie');
+
+    // Re-create a thingie.
+    $edit = array(
+      'id' => $id,
+      'name' => 'Thingie',
+    );
+    $this->drupalPost('admin/structure/config_test/add', $edit, 'Save');
+    $this->assertResponse(200);
+    $this->assertText('Thingie');
+
+    // Rename the thingie's ID/machine name.
+    $this->assertLinkByHref('admin/structure/config_test/manage/' . $id);
+    $new_id = 'zingie';
+    $edit = array(
+      'id' => $new_id,
+      'name' => 'Zingie',
+    );
+    $this->drupalPost('admin/structure/config_test/manage/' . $id, $edit, 'Save');
+    $this->assertResponse(200);
+    $this->assertNoText('Thingie');
+    $this->assertText('Zingie');
+  }
+}
diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigFileContentTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigFileContentTest.php
index bfd27ac..29fad3e 100644
--- a/core/modules/config/lib/Drupal/config/Tests/ConfigFileContentTest.php
+++ b/core/modules/config/lib/Drupal/config/Tests/ConfigFileContentTest.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\config\Tests;
 
+use Drupal\Core\Config\DatabaseStorage;
 use Drupal\Core\Config\FileStorage;
 use Drupal\simpletest\WebTestBase;
 
@@ -14,8 +15,6 @@ use Drupal\simpletest\WebTestBase;
  * Tests reading and writing file contents.
  */
 class ConfigFileContentTest extends WebTestBase {
-  protected $fileExtension;
-
   public static function getInfo() {
     return array(
       'name' => 'File content',
@@ -26,15 +25,14 @@ class ConfigFileContentTest extends WebTestBase {
 
   function setUp() {
     parent::setUp();
-
-    $this->fileExtension = FileStorage::getFileExtension();
   }
 
   /**
    * Tests setting, writing, and reading of a configuration setting.
    */
   function testReadWriteConfig() {
-    $config_dir = config_get_config_directory();
+    $database_storage = new DatabaseStorage();
+
     $name = 'foo.bar';
     $key = 'foo';
     $value = 'bar';
@@ -62,16 +60,15 @@ class ConfigFileContentTest extends WebTestBase {
     $config = config($name);
 
     // Verify an configuration object is returned.
-//    $this->assertEqual($config->name, $name);
+    $this->assertEqual($config->getName(), $name);
     $this->assertTrue($config, t('Config object created.'));
 
     // Verify the configuration object is empty.
     $this->assertEqual($config->get(), array(), t('New config object is empty.'));
 
     // Verify nothing was saved.
-    $db_config = db_query('SELECT * FROM {config} WHERE name = :name', array(':name' => $name))->fetch();
-    $this->assertIdentical($db_config, FALSE, t('Active store does not have a record for %name', array('%name' => $name)));
-    $this->assertFalse(file_exists($config_dir . '/' . $name . '.' . $this->fileExtension), 'Configuration file does not exist.');
+    $db_data = $database_storage->read($name);
+    $this->assertIdentical($db_data, array());
 
     // Add a top level value
     $config = config($name);
@@ -97,15 +94,12 @@ class ConfigFileContentTest extends WebTestBase {
     $config->save();
 
     // Verify the database entry exists.
-    $db_config = db_query('SELECT * FROM {config} WHERE name = :name', array(':name' => $name))->fetch();
-    $this->assertEqual($db_config->name, $name, t('After saving configuration, active store has a record for %name', array('%name' => $name)));
-
-    // Verify the file exists.
-    $this->assertTrue(file_exists($config_dir . '/' . $name . '.' . $this->fileExtension), t('After saving configuration, config file exists.'));
+    $db_data = $database_storage->read($name);
+    $this->assertTrue($db_data);
 
     // Read top level value
     $config = config($name);
-//    $this->assertEqual($config->name, $name);
+    $this->assertEqual($config->getName(), $name);
     $this->assertTrue($config, 'Config object created.');
     $this->assertEqual($config->get($key), 'bar', t('Top level configuration value found.'));
 
@@ -158,30 +152,27 @@ class ConfigFileContentTest extends WebTestBase {
     $config->set($key, $value)->save();
 
     // Verify the database entry exists from a chained save.
-    $db_config = db_query('SELECT * FROM {config} WHERE name = :name', array(':name' => $chained_name))->fetch();
-    $this->assertEqual($db_config->name, $chained_name, t('After saving configuration by chaining through set(), active store has a record for %name', array('%name' => $chained_name)));
-
-    // Verify the file exists from a chained save.
-    $this->assertTrue(file_exists($config_dir . '/' . $chained_name . '.' . $this->fileExtension), t('After saving configuration by chaining through set(), config file exists.'));
+    $db_data = $database_storage->read($chained_name);
+    $this->assertEqual($db_data, $config->get());
 
     // Get file listing for all files starting with 'foo'. Should return
     // two elements.
-    $files = FileStorage::getNamesWithPrefix('foo');
+    $files = $database_storage->getNamesWithPrefix('foo');
     $this->assertEqual(count($files), 2, 'Two files listed with the prefix \'foo\'.');
 
     // Get file listing for all files starting with 'biff'. Should return
     // one element.
-    $files = FileStorage::getNamesWithPrefix('biff');
+    $files = $database_storage->getNamesWithPrefix('biff');
     $this->assertEqual(count($files), 1, 'One file listed with the prefix \'biff\'.');
 
     // Get file listing for all files starting with 'foo.bar'. Should return
     // one element.
-    $files = FileStorage::getNamesWithPrefix('foo.bar');
+    $files = $database_storage->getNamesWithPrefix('foo.bar');
     $this->assertEqual(count($files), 1, 'One file listed with the prefix \'foo.bar\'.');
 
     // Get file listing for all files starting with 'bar'. Should return
     // an empty array.
-    $files = FileStorage::getNamesWithPrefix('bar');
+    $files = $database_storage->getNamesWithPrefix('bar');
     $this->assertEqual($files, array(), 'No files listed with the prefix \'bar\'.');
 
     // Delete the configuration.
@@ -189,17 +180,14 @@ class ConfigFileContentTest extends WebTestBase {
     $config->delete();
 
     // Verify the database entry no longer exists.
-    $db_config = db_query('SELECT * FROM {config} WHERE name = :name', array(':name' => $name))->fetch();
-    $this->assertIdentical($db_config, FALSE);
-    $this->assertFalse(file_exists($config_dir . '/' . $name . $this->fileExtension));
-
-    // Attempt to delete non-existing configuration.
+    $db_data = $database_storage->read($name);
+    $this->assertIdentical($db_data, array());
   }
 
   /**
    * Tests serialization of configuration to file.
    */
-  function testConfigSerialization() {
+  function testSerialization() {
     $name = $this->randomName(10) . '.' . $this->randomName(10);
     $config_data = array(
       // Indexed arrays; the order of elements is essential.
@@ -216,17 +204,10 @@ class ConfigFileContentTest extends WebTestBase {
       'invalid xml' => '</title><script type="text/javascript">alert("Title XSS!");</script> & < > " \' ',
     );
 
-    // Attempt to read non-existing configuration.
-    $config = config($name);
-
-    foreach ($config_data as $key => $value) {
-      $config->set($key, $value);
-    }
-
-    $config->save();
-
-    $config_filestorage = new FileStorage($name);
-    $config_parsed = $config_filestorage->read();
+    // Encode and write, and reload and decode the configuration data.
+    $filestorage = new FileStorage();
+    $filestorage->write($name, $config_data);
+    $config_parsed = $filestorage->read($name);
 
     $key = 'numeric keys';
     $this->assertIdentical($config_data[$key], $config_parsed[$key]);
diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigFileSecurityTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigFileSecurityTest.php
deleted file mode 100644
index 5f9ec07..0000000
--- a/core/modules/config/lib/Drupal/config/Tests/ConfigFileSecurityTest.php
+++ /dev/null
@@ -1,51 +0,0 @@
-<?php
-
-/**
- * @file
- * Definition of Drupal\config\Tests\ConfigFileSecurityTest.
- */
-
-namespace Drupal\config\Tests;
-
-use Drupal\Core\Config\FileStorage;
-use Drupal\simpletest\WebTestBase;
-
-/**
- * Tests the secure file writer.
- */
-class ConfigFileSecurityTest extends WebTestBase {
-  protected $filename = 'foo.bar';
-
-  protected $testContent = array('greeting' => 'Good morning, Denver!');
-
-  public static function getInfo() {
-    return array(
-      'name' => 'File security',
-      'description' => 'Tests security of saved configuration files.',
-      'group' => 'Configuration',
-    );
-  }
-
-  /**
-   * Tests that a file written by this system can be successfully read back.
-   */
-  function testFilePersist() {
-    $file = new FileStorage($this->filename);
-    $file->write($this->testContent);
-
-    unset($file);
-
-    // Reading should throw an exception in case of bad validation.
-    // Note that if any other exception is thrown, we let the test system
-    // handle catching and reporting it.
-    try {
-      $file = new FileStorage($this->filename);
-      $saved_content = $file->read();
-
-      $this->assertEqual($saved_content, $this->testContent);
-    }
-    catch (Exception $e) {
-      $this->fail('File failed verification when being read.');
-    }
-  }
-}
diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigImportTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigImportTest.php
new file mode 100644
index 0000000..09baded
--- /dev/null
+++ b/core/modules/config/lib/Drupal/config/Tests/ConfigImportTest.php
@@ -0,0 +1,162 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\config\Tests\ConfigImportTestCase.
+ */
+
+namespace Drupal\config\Tests;
+
+use Drupal\Core\Config\DatabaseStorage;
+use Drupal\Core\Config\FileStorage;
+use Drupal\simpletest\WebTestBase;
+
+/**
+ * Tests config_import() functionality.
+ */
+class ConfigImportTest extends WebTestBase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Import configuration',
+      'description' => 'Tests importing configuration from files into active store.',
+      'group' => 'Configuration',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('config_test');
+  }
+
+  /**
+   * Tests deletion of configuration during import.
+   */
+  function testDeleted() {
+    $name = 'config_test.system';
+    $dynamic_name = 'config_test.dynamic.default';
+
+    // Verify the default configuration values exist.
+    $config = config($name);
+    $this->assertIdentical($config->get('foo'), 'bar');
+    $config = config($dynamic_name);
+    $this->assertIdentical($config->get('id'), 'default');
+
+    // Export.
+    config_export();
+
+    // Delete the configuration objects.
+    $file_storage = new FileStorage();
+    $file_storage->delete($name);
+    $file_storage->delete($dynamic_name);
+
+    // Import.
+    config_import();
+
+    // Verify the values have disappeared.
+    $database_storage = new DatabaseStorage();
+    $this->assertIdentical($database_storage->read($name), array());
+    $this->assertIdentical($database_storage->read($dynamic_name), array());
+
+    $config = config($name);
+    $this->assertIdentical($config->get('foo'), NULL);
+    $config = config($dynamic_name);
+    $this->assertIdentical($config->get('id'), NULL);
+  }
+
+  /**
+   * Tests creation of configuration during import.
+   */
+  function testNew() {
+    $name = 'config_test.new';
+    $dynamic_name = 'config_test.dynamic.new';
+
+    // Verify the configuration to create does not exist yet.
+    $file_storage = new FileStorage();
+    $this->assertIdentical($file_storage->exists($name), FALSE, $name . ' not found.');
+    $this->assertIdentical($file_storage->exists($dynamic_name), FALSE, $dynamic_name . ' not found.');
+
+    // Export.
+    config_export();
+
+    // Create new configuration objects.
+    $file_storage->write($name, array(
+      'add_me' => 'new value',
+    ));
+    $file_storage->write($dynamic_name, array(
+      'id' => 'new',
+      'name' => 'New',
+    ));
+    $this->assertIdentical($file_storage->exists($name), TRUE, $name . ' found.');
+    $this->assertIdentical($file_storage->exists($dynamic_name), TRUE, $dynamic_name . ' found.');
+
+    // Import.
+    config_import();
+
+    // Verify the values appeared.
+    $config = config($name);
+    $this->assertIdentical($config->get('add_me'), 'new value');
+    $config = config($dynamic_name);
+    $this->assertIdentical($config->get('name'), 'New');
+  }
+
+  /**
+   * Tests updating of configuration during import.
+   */
+  function testUpdated() {
+    $name = 'config_test.system';
+    $dynamic_name = 'config_test.dynamic.default';
+
+    // Export.
+    config_export();
+
+    // Replace the file content of the existing configuration objects.
+    $file_storage = new FileStorage();
+    $this->assertIdentical($file_storage->exists($name), TRUE, $name . ' found.');
+    $this->assertIdentical($file_storage->exists($dynamic_name), TRUE, $dynamic_name . ' found.');
+    $file_storage->write($name, array(
+      'foo' => 'beer',
+    ));
+    $file_storage->write($dynamic_name, array(
+      'id' => 'default',
+      'name' => 'Updated',
+    ));
+
+    // Verify the active store still returns the default values.
+    $config = config($name);
+    $this->assertIdentical($config->get('foo'), 'bar');
+    $config = config($dynamic_name);
+    $this->assertIdentical($config->get('name'), 'Default');
+
+    // Import.
+    config_import();
+
+    // Verify the values were updated.
+    $config = config($name);
+    $this->assertIdentical($config->get('foo'), 'beer');
+    $config = config($dynamic_name);
+    $this->assertIdentical($config->get('name'), 'Updated');
+  }
+
+  /**
+   * Tests config_import() hook invocations.
+   */
+  function testSyncHooks() {
+    $name = 'config_test.system';
+    $dynamic_name = 'config_test.dynamic.default';
+
+    // Export.
+    config_export();
+
+    // Delete a file so that hook_config_import() hooks are run.
+    $file_storage = new FileStorage();
+    $this->assertIdentical($file_storage->exists($name), TRUE, $name . ' found.');
+    $this->assertIdentical($file_storage->exists($dynamic_name), TRUE, $dynamic_name . ' found.');
+    $file_storage->delete($name);
+    $file_storage->delete($dynamic_name);
+
+    // Import.
+    config_import();
+
+    // Verify hook_config_import() was invoked.
+    $this->assertIdentical($GLOBALS['hook_config_import'], 'config_test_config_import');
+  }
+}
diff --git a/core/modules/image/image.module b/core/modules/image/image.module
index f3bf83d..c95af19 100644
--- a/core/modules/image/image.module
+++ b/core/modules/image/image.module
@@ -500,6 +500,36 @@ 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. Good idea.
+    //   But squeezing that into a "delete" operation is the worst idea ever.
+    //   Regardless of Image module insanity, add a 'replaced' stack to
+    //   config_import()? And how can that work? If an 'old_ID' key would be a
+    //   standard, wouldn't this belong into 'changed' instead?
+    $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
diff --git a/core/modules/system/lib/Drupal/system/Tests/Module/EnableDisableTest.php b/core/modules/system/lib/Drupal/system/Tests/Module/EnableDisableTest.php
index 6319572..8afe33b 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Module/EnableDisableTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Module/EnableDisableTest.php
@@ -106,7 +106,7 @@ class EnableDisableTest extends ModuleTestBase {
           $this->assertText(t('hook_modules_enabled fired for @module', array('@module' => $module_to_enable)));
           $this->assertModules(array($module_to_enable), TRUE);
           $this->assertModuleTablesExist($module_to_enable);
-          $this->assertModuleConfigFilesExist($module_to_enable);
+          $this->assertModuleConfig($module_to_enable);
           $this->assertLogMessage('system', "%module module installed.", array('%module' => $module_to_enable), WATCHDOG_INFO);
           $this->assertLogMessage('system', "%module module enabled.", array('%module' => $module_to_enable), WATCHDOG_INFO);
         }
@@ -187,7 +187,7 @@ class EnableDisableTest extends ModuleTestBase {
     //  Check that the module's database tables still exist.
     $this->assertModuleTablesExist($module);
     //  Check that the module's config files still exist.
-    $this->assertModuleConfigFilesExist($module);
+    $this->assertModuleConfig($module);
 
     // Uninstall the module.
     $edit = array();
@@ -209,6 +209,6 @@ class EnableDisableTest extends ModuleTestBase {
     // Check that the module's database tables no longer exist.
     $this->assertModuleTablesDoNotExist($module);
     // Check that the module's config files no longer exist.
-    $this->assertModuleConfigFilesDoNotExist($module);
+    $this->assertNoModuleConfig($module);
   }
 }
diff --git a/core/modules/system/lib/Drupal/system/Tests/Module/ModuleTestBase.php b/core/modules/system/lib/Drupal/system/Tests/Module/ModuleTestBase.php
index 3b2ed5c..2c0712f 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Module/ModuleTestBase.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Module/ModuleTestBase.php
@@ -8,6 +8,7 @@
 namespace Drupal\system\Tests\Module;
 
 use Drupal\Core\Database\Database;
+use Drupal\Core\Config\DatabaseStorage;
 use Drupal\Core\Config\FileStorage;
 use Drupal\simpletest\WebTestBase;
 
@@ -77,65 +78,49 @@ class ModuleTestBase extends WebTestBase {
   }
 
   /**
-   * Assert that a module's config files have been loaded.
+   * Asserts that the default configuration of a module has been installed.
    *
    * @param string $module
    *   The name of the module.
    *
    * @return bool
-   *   TRUE if the module's config files exist, FALSE otherwise.
+   *   TRUE if configuration has been installed, FALSE otherwise.
    */
-  function assertModuleConfigFilesExist($module) {
-    // Define test variable.
-    $files_exist = TRUE;
-    // Get the path to the module's config dir.
+  function assertModuleConfig($module) {
     $module_config_dir = drupal_get_path('module', $module) . '/config';
-    if (is_dir($module_config_dir)) {
-      $files = glob($module_config_dir . '/*.' . FileStorage::getFileExtension());
-      $this->assertTrue($files);
-      $config_dir = config_get_config_directory();
-      // Get the filename of each config file.
-      foreach ($files as $file) {
-        $parts = explode('/', $file);
-        $filename = array_pop($parts);
-        if (!file_exists($config_dir . '/' . $filename)) {
-          $files_exist = FALSE;
-        }
-      }
+    if (!is_dir($module_config_dir)) {
+      return;
     }
+    $module_file_storage = new FileStorage(array('directory' => $module_config_dir));
+    $names = $module_file_storage->getNamesWithPrefix();
+
+    // Verify that the config directory is not empty.
+    $this->assertTrue($names);
 
-    return $this->assertTrue($files_exist, t('All config files defined by the @module module have been copied to the live config directory.', array('@module' => $module)));
+    // Look up each default configuration object name in the active store, and
+    // if it exists, remove it from the stack.
+    foreach ($names as $key => $name) {
+      if (config($name)->get()) {
+        unset($names[$key]);
+      }
+    }
+    // Verify that all configuration has been installed (which means that $names
+    // is empty).
+    return $this->assertFalse($names, format_string('All default configuration of @module module found.', array('@module' => $module)));
   }
 
   /**
-   * Assert that none of a module's default config files are loaded.
+   * Asserts that no configuration exists for a given module.
    *
    * @param string $module
    *   The name of the module.
    *
    * @return bool
-   *   TRUE if the module's config files do not exist, FALSE otherwise.
+   *   TRUE if no configuration was found, FALSE otherwise.
    */
-  function assertModuleConfigFilesDoNotExist($module) {
-    // Define test variable.
-    $files_exist = FALSE;
-    // Get the path to the module's config dir.
-    $module_config_dir = drupal_get_path('module', $module) . '/config';
-    if (is_dir($module_config_dir)) {
-      $files = glob($module_config_dir . '/*.' . FileStorage::getFileExtension());
-      $this->assertTrue($files);
-      $config_dir = config_get_config_directory();
-      // Get the filename of each config file.
-      foreach ($files as $file) {
-        $parts = explode('/', $file);
-        $filename = array_pop($parts);
-        if (file_exists($config_dir . '/' . $filename)) {
-          $files_exist = TRUE;
-        }
-      }
-    }
-
-    return $this->assertFalse($files_exist, t('All config files defined by the @module module have been deleted from the live config directory.', array('@module' => $module)));
+  function assertNoModuleConfig($module) {
+    $names = config_get_storage_names_with_prefix($module . '.');
+    return $this->assertFalse($names, format_string('No configuration found for @module module.', array('@module' => $module)));
   }
 
   /**
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index b9558e5..32cfb75 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -379,7 +379,8 @@ function system_element_info() {
   $types['email'] = array(
     '#input' => TRUE,
     '#size' => 60,
-    '#maxlength' => EMAIL_MAX_LENGTH,
+    // user.module is not loaded in case of early bootstrap errors.
+    '#maxlength' => defined('EMAIL_MAX_LENGTH') ? EMAIL_MAX_LENGTH : 255,
     '#autocomplete_path' => FALSE,
     '#process' => array('form_process_autocomplete', 'ajax_process_form', 'form_process_pattern'),
     '#element_validate' => array('form_validate_email'),
