diff --git a/core/lib/Drupal/Core/Config/ConfigImporter.php b/core/lib/Drupal/Core/Config/ConfigImporter.php
index 2ccbf94..c75ded1 100644
--- a/core/lib/Drupal/Core/Config/ConfigImporter.php
+++ b/core/lib/Drupal/Core/Config/ConfigImporter.php
@@ -11,6 +11,7 @@
 use Drupal\Core\Extension\ThemeHandlerInterface;
 use Drupal\Component\Utility\String;
 use Drupal\Core\Config\Entity\ImportableEntityStorageInterface;
+use Drupal\Core\Config\ConfigEvents;
 use Drupal\Core\DependencyInjection\DependencySerialization;
 use Drupal\Core\Entity\EntityStorageException;
 use Drupal\Core\Lock\LockBackendInterface;
@@ -263,12 +264,12 @@ protected function getEmptyExtensionsProcessedList() {
    *
    * @param array $ops
    *   The operations to check for changes. Defaults to all operations, i.e.
-   *   array('delete', 'create', 'update').
+   *   array('delete', 'create', 'update', 'rename').
    *
    * @return bool
    *   TRUE if there are changes to process and FALSE if not.
    */
-  public function hasUnprocessedConfigurationChanges($ops = array('delete', 'create', 'update')) {
+  public function hasUnprocessedConfigurationChanges($ops = array('delete', 'create', 'rename', 'update')) {
     foreach ($ops as $op) {
       if (count($this->getUnprocessedConfiguration($op))) {
         return TRUE;
@@ -291,7 +292,7 @@ public function getProcessedConfiguration() {
    * Sets a change as processed.
    *
    * @param string $op
-   *   The change operation performed, either delete, create or update.
+   *   The change operation performed, either delete, create, rename, or update.
    * @param string $name
    *   The name of the configuration processed.
    */
@@ -304,7 +305,7 @@ protected function setProcessedConfiguration($op, $name) {
    *
    * @param string $op
    *   The change operation to get the unprocessed list for, either delete,
-   *   create or update.
+   *   create, rename, or update.
    *
    * @return array
    *   An array of configuration names.
@@ -569,7 +570,7 @@ public function processConfigurations(array &$context) {
     // into account.
     if ($this->totalConfigurationToProcess == 0) {
       $this->storageComparer->reset();
-      foreach (array('delete', 'create', 'update') as $op) {
+      foreach (array('delete', 'create', 'rename', 'update') as $op) {
         foreach ($this->getUnprocessedConfiguration($op) as $name) {
           $this->totalConfigurationToProcess += count($this->getUnprocessedConfiguration($op));
         }
@@ -645,7 +646,7 @@ protected function getNextExtensionOperation() {
   protected function getNextConfigurationOperation() {
     // The order configuration operations is processed is important. Deletes
     // have to come first so that recreates can work.
-    foreach (array('delete', 'create', 'update') as $op) {
+    foreach (array('delete', 'create', 'rename', 'update') as $op) {
       $config_names = $this->getUnprocessedConfiguration($op);
       if (!empty($config_names)) {
         return array(
@@ -668,6 +669,19 @@ protected function getNextConfigurationOperation() {
    */
   public function validate() {
     if (!$this->validated) {
+      // Validate renames.
+      foreach ($this->getUnprocessedConfiguration('rename') as $name) {
+        $names = $this->storageComparer->extractRenameNames($name);
+        $old_entity_type_id = $this->configManager->getEntityTypeIdByName($names['old_name']);
+        $new_entity_type_id = $this->configManager->getEntityTypeIdByName($names['new_name']);
+        if ($old_entity_type_id != $new_entity_type_id) {
+          $this->logError($this->t('Entity type mismatch on rename. !old_type not equal to !new_type for existing configuration !old_name and staged configuration !new_name.', array('old_type' => $old_entity_type_id, 'new_type' => $new_entity_type_id, 'old_name' => $names['old_name'], 'new_name' => $names['new_name'])));
+        }
+        // Has to be a configuration entity.
+        if (!$old_entity_type_id) {
+          $this->logError($this->t('Rename operation for simple configuration. Existing configuration !old_name and staged configuration !new_name.', array('old_name' => $names['old_name'], 'new_name' => $names['new_name'])));
+        }
+      }
       $this->eventDispatcher->dispatch(ConfigEvents::IMPORT_VALIDATE, new ConfigImporterEvent($this));
       if (count($this->getErrors())) {
         throw new ConfigImporterException('There were errors validating the config synchronization.');
@@ -770,6 +784,20 @@ protected function processExtension($type, $op, $name) {
    *   TRUE is to continue processing, FALSE otherwise.
    */
   protected function checkOp($op, $name) {
+    if ($op == 'rename') {
+      $names = $this->storageComparer->extractRenameNames($name);
+      $target_exists = $this->storageComparer->getTargetStorage()->exists($names['new_name']);
+      if ($target_exists) {
+        // If the target exists, the rename has already occurred as the
+        // result of a secondary configuration write. Change the operation
+        // into an update. This is the desired behavior since renames often
+        // have to occur together. For example, renaming a node type must
+        // also result in renaming its field instances and entity displays.
+        $this->storageComparer->moveRenameToUpdate($name);
+        return FALSE;
+      }
+      return TRUE;
+    }
     $target_exists = $this->storageComparer->getTargetStorage()->exists($name);
     switch ($op) {
       case 'delete':
@@ -845,7 +873,7 @@ protected function importConfig($op, $name) {
    *
    * @param string $op
    *   The change operation to get the unprocessed list for, either delete,
-   *   create or update.
+   *   create, rename, or update.
    * @param string $name
    *   The name of the configuration to process.
    *
@@ -858,6 +886,10 @@ protected function importConfig($op, $name) {
    *   otherwise.
    */
   protected function importInvokeOwner($op, $name) {
+    // Renames are handled separately.
+    if ($op == 'rename') {
+      return $this->importInvokeRename($name);
+    }
     // Validate the configuration object name before importing it.
     // Config::validateName($name);
     if ($entity_type = $this->configManager->getEntityTypeIdByName($name)) {
@@ -883,6 +915,45 @@ protected function importInvokeOwner($op, $name) {
       $this->setProcessedConfiguration($op, $name);
       return TRUE;
     }
+    return FALSE;
+  }
+
+  /**
+   * Imports a configuration entity rename.
+   *
+   * @param string $rename_name
+   *   The rename configuration name, as provided by
+   *   ConfigImporter::createRenameName().
+   *
+   * @return bool
+   *   TRUE if the configuration was imported as a configuration entity. FALSE
+   *   otherwise.
+   *
+   * @see \Drupal\Core\Config\ConfigImporter::createRenameName()
+   */
+  protected function importInvokeRename($rename_name) {
+    $names = $this->storageComparer->extractRenameNames($rename_name);
+    $entity_type_id = $this->configManager->getEntityTypeIdByName($names['old_name']);
+    $old_config = new Config($names['old_name'], $this->storageComparer->getTargetStorage(), $this->eventDispatcher, $this->typedConfigManager);
+    if ($old_data = $this->storageComparer->getTargetStorage()->read($names['old_name'])) {
+      $old_config->initWithData($old_data);
+    }
+
+    $data = $this->storageComparer->getSourceStorage()->read($names['new_name']);
+    $new_config = new Config($names['new_name'], $this->storageComparer->getTargetStorage(), $this->eventDispatcher, $this->typedConfigManager);
+    if ($data !== FALSE) {
+      $new_config->setData($data);
+    }
+
+    $entity_storage = $this->configManager->getEntityManager()->getStorage($entity_type_id);
+    // Call to the configuration entity's storage to handle the configuration
+    // change.
+    if (!($entity_storage instanceof ImportableEntityStorageInterface)) {
+      throw new EntityStorageException(String::format('The entity storage "@storage" for the "@entity_type" entity type does not support imports', array('@storage' => get_class($entity_storage), '@entity_type' => $entity_type_id)));
+    }
+    $entity_storage->importRename($names['old_name'], $new_config, $old_config);
+    $this->setProcessedConfiguration('rename', $rename_name);
+    return TRUE;
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Config/ConfigManager.php b/core/lib/Drupal/Core/Config/ConfigManager.php
index 6fd55c9..5a869d3 100644
--- a/core/lib/Drupal/Core/Config/ConfigManager.php
+++ b/core/lib/Drupal/Core/Config/ConfigManager.php
@@ -100,7 +100,10 @@ public function getConfigFactory() {
   /**
    * {@inheritdoc}
    */
-  public function diff(StorageInterface $source_storage, StorageInterface $target_storage, $name) {
+  public function diff(StorageInterface $source_storage, StorageInterface $target_storage, $source_name, $target_name = NULL) {
+    if (!isset($target_name)) {
+      $target_name = $source_name;
+    }
     // @todo Replace with code that can be autoloaded.
     //   https://drupal.org/node/1848266
     require_once __DIR__ . '/../../Component/Diff/DiffEngine.php';
@@ -111,8 +114,8 @@ public function diff(StorageInterface $source_storage, StorageInterface $target_
     $dumper = new Dumper();
     $dumper->setIndentation(2);
 
-    $source_data = explode("\n", $dumper->dump($source_storage->read($name), PHP_INT_MAX));
-    $target_data = explode("\n", $dumper->dump($target_storage->read($name), PHP_INT_MAX));
+    $source_data = explode("\n", $dumper->dump($source_storage->read($source_name), PHP_INT_MAX));
+    $target_data = explode("\n", $dumper->dump($target_storage->read($target_name), PHP_INT_MAX));
 
     // Check for new or removed files.
     if ($source_data === array('false')) {
diff --git a/core/lib/Drupal/Core/Config/ConfigManagerInterface.php b/core/lib/Drupal/Core/Config/ConfigManagerInterface.php
index 4da9474..1d35637 100644
--- a/core/lib/Drupal/Core/Config/ConfigManagerInterface.php
+++ b/core/lib/Drupal/Core/Config/ConfigManagerInterface.php
@@ -46,15 +46,18 @@ public function getConfigFactory();
    *   The storage to diff configuration from.
    * @param \Drupal\Core\Config\StorageInterface $target_storage
    *   The storage to diff configuration to.
-   * @param string $name
-   *   The name of the configuration object to diff.
+   * @param string $source_name
+   *   The name of the configuration object in the source storage to diff.
+   * @param string $target_name
+   *   (optional) The name of the configuration object in the target storage.
+   *   If omitted, the source name is used.
    *
    * @return core/lib/Drupal/Component/Diff
    *   A formatted string showing the difference between the two storages.
    *
    * @todo Make renderer injectable
    */
-  public function diff(StorageInterface $source_storage, StorageInterface $target_storage, $name);
+  public function diff(StorageInterface $source_storage, StorageInterface $target_storage, $source_name, $target_name = NULL);
 
   /**
    * Creates a configuration snapshot following a successful import.
diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php
index 126275a..1fd73e7 100644
--- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php
+++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php
@@ -455,4 +455,19 @@ public function importDelete($name, Config $new_config, Config $old_config) {
     return TRUE;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function importRename($old_name, Config $new_config, Config $old_config) {
+    $id = static::getIDFromConfigName($old_name, $this->entityType->getConfigPrefix());
+    $entity = $this->load($id);
+    $entity->setSyncing(TRUE);
+    $data = $new_config->get();
+    foreach ($data as $key => $value) {
+      $entity->set($key, $value);
+    }
+    $entity->save();
+    return TRUE;
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Config/Entity/ImportableEntityStorageInterface.php b/core/lib/Drupal/Core/Config/Entity/ImportableEntityStorageInterface.php
index 4eae41e..a12f770 100644
--- a/core/lib/Drupal/Core/Config/Entity/ImportableEntityStorageInterface.php
+++ b/core/lib/Drupal/Core/Config/Entity/ImportableEntityStorageInterface.php
@@ -56,4 +56,16 @@ public function importUpdate($name, Config $new_config, Config $old_config);
    */
   public function importDelete($name, Config $new_config, Config $old_config);
 
+  /**
+   * Renames entities upon synchronizing configuration changes.
+   *
+   * @param string $old_name
+   *   The original 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.
+   */
+  public function importRename($old_name, Config $new_config, Config $old_config);
+
 }
diff --git a/core/lib/Drupal/Core/Config/StorageComparer.php b/core/lib/Drupal/Core/Config/StorageComparer.php
index b30db17..929d57b 100644
--- a/core/lib/Drupal/Core/Config/StorageComparer.php
+++ b/core/lib/Drupal/Core/Config/StorageComparer.php
@@ -100,6 +100,7 @@ public function getEmptyChangelist() {
       'create' => array(),
       'update' => array(),
       'delete' => array(),
+      'rename' => array(),
     );
   }
 
@@ -117,7 +118,7 @@ public function getChangelist($op = NULL) {
    * Adds changes to the changelist.
    *
    * @param string $op
-   *   The change operation performed. Either delete, create or update.
+   *   The change operation performed. Either delete, create, rename, or update.
    * @param array $changes
    *   Array of changes to add to the changelist.
    * @param array $sort_order
@@ -147,6 +148,7 @@ public function createChangelist() {
     $this->addChangelistCreate();
     $this->addChangelistUpdate();
     $this->addChangelistDelete();
+    $this->addChangelistRename();
     $this->sourceData = NULL;
     $this->targetData = NULL;
     return $this;
@@ -209,6 +211,72 @@ protected function addChangelistUpdate() {
   }
 
   /**
+   * Creates the rename changelist.
+   *
+   * The list of renames is created from the different source and target names
+   * with same UUID. These changes will be removed from the create and delete
+   * lists.
+   */
+  protected function addChangelistRename() {
+    // Renames will be present in both the create and delete lists.
+    $create_list = $this->getChangelist('create');
+    $delete_list = $this->getChangelist('delete');
+    if (empty($create_list) || empty($delete_list)) {
+      return;
+    }
+
+    $create_uuids = array();
+    foreach ($this->sourceData as $id => $data) {
+      if (isset($data['uuid']) && in_array($id, $create_list)) {
+        $create_uuids[$data['uuid']] = $id;
+      }
+    }
+    if (empty($create_uuids)) {
+      return;
+    }
+
+    $renames = array();
+    foreach ($this->targetData as $id => $data) {
+      if (isset($data['uuid']) && isset($create_uuids[$data['uuid']])) {
+        // Remove the item from the create list.
+        $this->removeFromChangelist('create', $create_uuids[$data['uuid']]);
+        // Remove the item from the delete list.
+        $this->removeFromChangelist('delete', $id);
+        // Create the rename name.
+        $renames[] = $this->createRenameName($id, $create_uuids[$data['uuid']]);
+      }
+    }
+
+    // Import the renames in reverse order, so that (e.g.) content types are
+    // handled before fields.
+    $this->addChangeList('rename', array_reverse($renames));
+  }
+
+  /**
+   * Removes the entry from the given operation changelist for the given name.
+   *
+   * @param string $op
+   *   The changelist to act on. Either delete, create, rename or update.
+   * @param string $name
+   *   The name of the configuration to remove.
+   */
+  protected function removeFromChangelist($op, $name) {
+    $key = array_search($name, $this->changelist[$op]);
+    if ($key !== FALSE) {
+      unset($this->changelist[$op][$key]);
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function moveRenameToUpdate($rename) {
+    $names = $this->extractRenameNames($rename);
+    $this->removeFromChangelist('rename', $rename);
+    $this->addChangeList('update', array($names['new_name']), $this->sourceNames);
+  }
+
+  /**
    * {@inheritdoc}
    */
   public function reset() {
@@ -220,7 +288,7 @@ public function reset() {
   /**
    * {@inheritdoc}
    */
-  public function hasChanges($ops = array('delete', 'create', 'update')) {
+  public function hasChanges($ops = array('delete', 'create', 'update', 'rename')) {
     foreach ($ops as $op) {
       if (!empty($this->changelist[$op])) {
         return TRUE;
@@ -249,4 +317,31 @@ protected function getAndSortConfigData() {
     $this->sourceNames = $dependency_manager->setData($this->sourceData)->sortAll();
   }
 
+  /**
+   * Creates a rename name from the old and new names for the object.
+   *
+   * @param string $old_name
+   *   The old configuration object name.
+   * @param string $new_name
+   *   The new configuration object name.
+   *
+   * @return string
+   *   The configuration change name that encodes both the old and the new name.
+   *
+   * @see \Drupal\Core\Config\StorageComparerInterface::extractRenameNames()
+   */
+  protected function createRenameName($name1, $name2) {
+    return $name1 . '::' . $name2;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function extractRenameNames($name) {
+    $names = explode('::', $name, 2);
+    return array(
+      'old_name' => $names[0],
+      'new_name' => $names[1],
+    );
+  }
 }
diff --git a/core/lib/Drupal/Core/Config/StorageComparerInterface.php b/core/lib/Drupal/Core/Config/StorageComparerInterface.php
index e8c597d..f85a8aa 100644
--- a/core/lib/Drupal/Core/Config/StorageComparerInterface.php
+++ b/core/lib/Drupal/Core/Config/StorageComparerInterface.php
@@ -80,4 +80,30 @@ public function hasChanges($ops = array('delete', 'create', 'update'));
    */
   public function validateSiteUuid();
 
+  /**
+   * Moves a rename operation to an update.
+   *
+   * @param string $rename
+   *   The rename name, as provided by ConfigImporter::createRenameName().
+   *
+   * @see \Drupal\Core\Config\ConfigImporter::createRenameName()
+   */
+  public function moveRenameToUpdate($rename);
+
+  /**
+   * Extracts old and new configuration names from a configuration change name.
+   *
+   * @param string $name
+   *   The configuration change name, as provided by
+   *   ConfigImporter::createRenameName().
+   *
+   * @return array
+   *   An associative array of configuration names. The array keys are
+   *   'old_name' and and 'new_name' representing the old and name configuration
+   *   object names during a rename operation.
+   *
+   * @see \Drupal\Core\Config\StorageComparer::createRenameNames()
+   */
+  public function extractRenameNames($name);
+
 }
diff --git a/core/modules/config/config.routing.yml b/core/modules/config/config.routing.yml
index bd0d5c5..f2a944a 100644
--- a/core/modules/config/config.routing.yml
+++ b/core/modules/config/config.routing.yml
@@ -7,9 +7,10 @@ config.sync:
     _permission: 'synchronize configuration'
 
 config.diff:
-  path: '/admin/config/development/configuration/sync/diff/{config_file}'
+  path: '/admin/config/development/configuration/sync/diff/{source_name}/{target_name}'
   defaults:
     _content: '\Drupal\config\Controller\ConfigController::diff'
+    target_name: NULL
   requirements:
     _permission: 'synchronize configuration'
 
diff --git a/core/modules/config/lib/Drupal/config/Controller/ConfigController.php b/core/modules/config/lib/Drupal/config/Controller/ConfigController.php
index c79b8cb..dd7a0c3 100644
--- a/core/modules/config/lib/Drupal/config/Controller/ConfigController.php
+++ b/core/modules/config/lib/Drupal/config/Controller/ConfigController.php
@@ -105,15 +105,15 @@ public function downloadExport() {
    * @return string
    *   Table showing a two-way diff between the active and staged configuration.
    */
-  public function diff($config_file) {
+  public function diff($source_name, $target_name = NULL) {
 
-    $diff = $this->configManager->diff($this->targetStorage, $this->sourceStorage, $config_file);
+    $diff = $this->configManager->diff($this->targetStorage, $this->sourceStorage, $source_name, $target_name);
     $formatter = new \DrupalDiffFormatter();
     $formatter->show_header = FALSE;
 
     $build = array();
 
-    $build['#title'] = t('View changes of @config_file', array('@config_file' => $config_file));
+    $build['#title'] = t('View changes of @config_file', array('@config_file' => $source_name));
     // Add the CSS for the inline diff.
     $build['#attached']['css'][] = drupal_get_path('module', 'system') . '/css/system.diff.css';
 
diff --git a/core/modules/config/lib/Drupal/config/Form/ConfigSync.php b/core/modules/config/lib/Drupal/config/Form/ConfigSync.php
index a505a6c..48f509c 100644
--- a/core/modules/config/lib/Drupal/config/Form/ConfigSync.php
+++ b/core/modules/config/lib/Drupal/config/Form/ConfigSync.php
@@ -207,6 +207,10 @@ public function buildForm(array $form, array &$form_state) {
         case 'delete':
           $form[$config_change_type]['heading']['#value'] = format_plural(count($config_files), '@count removed', '@count removed');
           break;
+
+        case 'rename':
+          $form[$config_change_type]['heading']['#value'] = format_plural(count($config_files), '@count renamed', '@count renamed');
+          break;
       }
       $form[$config_change_type]['list'] = array(
         '#type' => 'table',
@@ -214,9 +218,18 @@ public function buildForm(array $form, array &$form_state) {
       );
 
       foreach ($config_files as $config_file) {
+        if ($config_change_type == 'rename') {
+          $names = explode('::', $config_file);
+          $href = $this->urlGenerator->getPathFromRoute('config.diff', array('source_name' => $names[0], 'target_name' => $names[1]));
+          $config_name = $this->t('!source_name to !target_name', array('!source_name' => $names[0], '!target_name' => $names[1]));
+        }
+        else {
+          $href = $this->urlGenerator->getPathFromRoute('config.diff', array('source_name' => $config_file));
+          $config_name = $config_file;
+        }
         $links['view_diff'] = array(
           'title' => $this->t('View differences'),
-          'href' => $this->urlGenerator->getPathFromRoute('config.diff', array('config_file' => $config_file)),
+          'href' => $href,
           'attributes' => array(
             'class' => array('use-ajax'),
             'data-accepts' => 'application/vnd.drupal-modal',
@@ -226,7 +239,7 @@ public function buildForm(array $form, array &$form_state) {
           ),
         );
         $form[$config_change_type]['list']['#rows'][] = array(
-          'name' => $config_file,
+          'name' => $config_name,
           'operations' => array(
             'data' => array(
               '#type' => 'operations',
diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigDiffTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigDiffTest.php
index 57e0553..6f3b3de 100644
--- a/core/modules/config/lib/Drupal/config/Tests/ConfigDiffTest.php
+++ b/core/modules/config/lib/Drupal/config/Tests/ConfigDiffTest.php
@@ -84,6 +84,33 @@ function testDiff() {
     $this->assertEqual($diff->edits[1]->type, 'add', 'The second item in the diff is an add.');
     $this->assertFalse($diff->edits[1]->orig, format_string("The key '%add_key' does not exist in active.", array('%add_key' => $add_key)));
     $this->assertEqual($diff->edits[1]->closing[0], $add_key . ': ' . $add_data, format_string("The staging value for key '%add_key' is '%add_data'.", array('%add_key' => $add_key, '%add_data' => $add_data)));
+
+    // Test diffing a renamed config entity.
+    $test_entity_id = $this->randomName();
+    $test_entity = entity_create('config_test', array(
+      'id' => $test_entity_id,
+      'label' => $this->randomName(),
+    ));
+    $test_entity->save();
+    $data = $active->read('config_test.dynamic.' . $test_entity_id);
+    $staging->write('config_test.dynamic.' . $test_entity_id, $data);
+    $config_name = 'config_test.dynamic.' . $test_entity_id;
+    $diff = \Drupal::service('config.manager')->diff($active, $staging, $config_name, $config_name);
+    // Prove the fields match.
+    $this->assertEqual($diff->edits[0]->type, 'copy',  'The first item in the diff is a copy.');
+    $this->assertEqual(count($diff->edits), 1, 'There is one item in the diff');
+
+    // Rename the entity.
+    $new_test_entity_id = $this->randomName();
+    $test_entity->set('id', $new_test_entity_id);
+    $test_entity->save();
+
+    $diff = \Drupal::service('config.manager')->diff($active, $staging, 'config_test.dynamic.' . $new_test_entity_id, $config_name);
+    $this->assertEqual($diff->edits[0]->type, 'change',  'The second item in the diff is a copy.');
+    $this->assertEqual($diff->edits[0]->orig, array('id: ' . $new_test_entity_id));
+    $this->assertEqual($diff->edits[0]->closing, array('id: ' . $test_entity_id));
+    $this->assertEqual($diff->edits[1]->type, 'copy',  'The second item in the diff is a copy.');
+    $this->assertEqual(count($diff->edits), 2, 'There are two items in the diff.');
   }
 
-}
\ No newline at end of file
+}
diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigImportRenameTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigImportRenameTest.php
new file mode 100644
index 0000000..2b792c5
--- /dev/null
+++ b/core/modules/config/lib/Drupal/config/Tests/ConfigImportRenameTest.php
@@ -0,0 +1,125 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\config\Tests\ConfigImportRenameTest.
+ */
+
+namespace Drupal\config\Tests;
+
+use Drupal\Component\Utility\String;
+use Drupal\Component\Utility\Unicode;
+use Drupal\Core\Config\ConfigImporter;
+use Drupal\Core\Config\ConfigImporterException;
+use Drupal\Core\Config\Entity\ConfigEntityStorage;
+use Drupal\Core\Config\StorageComparer;
+use Drupal\simpletest\DrupalUnitTestBase;
+use Drupal\simpletest\WebTestBase;
+
+/**
+ * Tests importing renamed configuration from files into active configuration.
+ */
+class ConfigImportRenameTest extends WebTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('system', 'node', 'field', 'text', 'entity', 'config', 'config_test');
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Import renamed configuration',
+      'description' => 'Tests importing renamed configuration.',
+      'group' => 'Configuration',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setUp() {
+    parent::setUp();
+    $this->web_user = $this->drupalCreateUser(array('synchronize configuration'));
+    $this->drupalLogin($this->web_user);
+  }
+
+  /**
+   * Tests configuration renaming.
+   */
+  public function testConfigurationRename() {
+    $content_type = entity_create('node_type', array(
+      'type' => Unicode::strtolower($this->randomName(16)),
+      'name' => $this->randomName(),
+    ));
+    $content_type->save();
+    $staged_type = $content_type->type;
+    $active = $this->container->get('config.storage');
+    $staging = $this->container->get('config.storage.staging');
+
+    $config_name = $content_type->getEntityType()->getConfigPrefix() . '.' . $content_type->id();
+    // Emulate a staging operation.
+    $this->copyConfig($active, $staging);
+
+    // Change the machine name of the content type.
+    $content_type->type = Unicode::strtolower($this->randomName(8));
+    $content_type->save();
+    $active_type = $content_type->type;
+    $renamed_config_name = $content_type->getEntityType()->getConfigPrefix() . '.' . $content_type->id();
+    $this->assertTrue($active->exists($renamed_config_name), 'The content type has the new name in the active store.');
+    $this->assertFalse($active->exists($config_name), "The content type's old name does not exist active store.");
+
+    $this->configImporter()->reset();
+    $this->assertEqual(0, count($this->configImporter()->getUnprocessedConfiguration('create')), 'There are no configuration items to create.');
+    $this->assertEqual(0, count($this->configImporter()->getUnprocessedConfiguration('delete')), 'There are no configuration items to delete.');
+    $this->assertEqual(0, count($this->configImporter()->getUnprocessedConfiguration('update')), 'There are no configuration items to update.');
+
+    // We expect that changing the machine name of the content type will
+    // rename five configuration entities: the node type, the body field
+    // instance, two entity form displays, and the entity view display.
+    $expected = array(
+      'node.type.' . $active_type . '::node.type.' . $staged_type,
+      'field.instance.node.' . $active_type . '.body::field.instance.node.' . $staged_type . '.body',
+      'entity.view_display.node.' . $active_type . '.teaser::entity.view_display.node.' . $staged_type . '.teaser',
+      'entity.view_display.node.' . $active_type . '.default::entity.view_display.node.' . $staged_type . '.default',
+      'entity.form_display.node.' . $active_type . '.default::entity.form_display.node.' . $staged_type . '.default',
+    );
+    $renames = $this->configImporter()->getUnprocessedConfiguration('rename');
+    $this->assertIdentical($expected, $renames);
+
+    $this->drupalGet('admin/config/development/configuration');
+    foreach ($expected as $rename) {
+      $names = $this->configImporter()->getStorageComparer()->extractRenameNames($rename);
+      $this->assertText(String::format('!source_name to !target_name', array('!source_name' => $names['old_name'], '!target_name' => $names['new_name'])));
+      // Test that the diff link is present for each renamed item.
+      $href = \Drupal::urlGenerator()->getPathFromRoute('config.diff', array('source_name' => $names['old_name'], 'target_name' => $names['new_name']));
+      $this->assertLinkByHref($href);
+      $hrefs[$rename] = $href;
+    }
+
+    // Ensure that the diff works for each renamed item.
+    foreach ($hrefs as $rename => $href) {
+      $this->drupalGet($href);
+      $names = $this->configImporter()->getStorageComparer()->extractRenameNames($rename);
+      $config_entity_type = \Drupal::service('config.manager')->getEntityTypeIdByName($names['old_name']);
+      $entity_type = \Drupal::entityManager()->getDefinition($config_entity_type);
+      $old_id = ConfigEntityStorage::getIDFromConfigName($names['old_name'], $entity_type->getConfigPrefix());
+      $new_id = ConfigEntityStorage::getIDFromConfigName($names['new_name'], $entity_type->getConfigPrefix());
+      $this->assertText('-' . $entity_type->getKey('id') . ': ' . $old_id);
+      $this->assertText('+' . $entity_type->getKey('id') . ': ' . $new_id);
+    }
+
+    // Run the import.
+    $this->drupalPostForm('admin/config/development/configuration', array(), t('Import all'));
+    $this->assertText(t('There are no configuration changes.'));
+
+    $this->assertFalse(entity_load('node_type', $active_type), 'The content no longer exists with the old name.');
+    $content_type = entity_load('node_type', $staged_type);
+    $this->assertIdentical($staged_type, $content_type->type);
+  }
+
+}
diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigImportRenameValidationTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigImportRenameValidationTest.php
new file mode 100644
index 0000000..380a324
--- /dev/null
+++ b/core/modules/config/lib/Drupal/config/Tests/ConfigImportRenameValidationTest.php
@@ -0,0 +1,124 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\config\Tests\ConfigImportRenameValidationTest.
+ */
+
+namespace Drupal\config\Tests;
+
+use Drupal\Component\Utility\String;
+use Drupal\Component\Utility\Unicode;
+use Drupal\Core\Config\ConfigImporter;
+use Drupal\Core\Config\ConfigImporterException;
+use Drupal\Core\Config\StorageComparer;
+use Drupal\simpletest\DrupalUnitTestBase;
+
+/**
+ * Tests validating renamed configuration in a configuration import.
+ */
+class ConfigImportRenameValidationTest extends DrupalUnitTestBase {
+
+  /**
+   * Config Importer object used for testing.
+   *
+   * @var \Drupal\Core\Config\ConfigImporter
+   */
+  protected $configImporter;
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('system', 'node', 'field', 'text', 'entity', 'config_test');
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Configuration import rename validation',
+      'description' => 'Tests validating renamed configuration in a configuration import.',
+      'group' => 'Configuration',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setUp() {
+    parent::setUp();
+
+    $this->installSchema('system', 'config_snapshot');
+    $this->installSchema('node', 'node');
+
+    // Set up the ConfigImporter object for testing.
+    $storage_comparer = new StorageComparer(
+      $this->container->get('config.storage.staging'),
+      $this->container->get('config.storage')
+    );
+    $this->configImporter = new ConfigImporter(
+      $storage_comparer->createChangelist(),
+      $this->container->get('event_dispatcher'),
+      $this->container->get('config.manager'),
+      $this->container->get('lock'),
+      $this->container->get('config.typed'),
+      $this->container->get('module_handler'),
+      $this->container->get('theme_handler'),
+      $this->container->get('string_translation')
+    );
+  }
+
+  /**
+   * Tests configuration renaming validation.
+   */
+  public function testRenameValidation() {
+    // Create a test entity.
+    $test_entity_id = $this->randomName();
+    $test_entity = entity_create('config_test', array(
+      'id' => $test_entity_id,
+      'label' => $this->randomName(),
+    ));
+    $test_entity->save();
+    $uuid = $test_entity->uuid();
+
+    // Stage the test entity and then delete it from the active storage.
+    $active = $this->container->get('config.storage');
+    $staging = $this->container->get('config.storage.staging');
+    $this->copyConfig($active, $staging);
+    $test_entity->delete();
+
+    // Create a content type with a matching UUID in the active storage.
+    $content_type = entity_create('node_type', array(
+      'type' => Unicode::strtolower($this->randomName(16)),
+      'name' => $this->randomName(),
+      'uuid' => $uuid,
+    ));
+    $content_type->save();
+
+    // Confirm that the staged configuration is detected as a rename since the
+    // UUIDs match.
+    $this->configImporter->reset();
+    $expected = array(
+      'node.type.' . $content_type->id() . '::config_test.dynamic.' . $test_entity_id,
+    );
+    $renames = $this->configImporter->getUnprocessedConfiguration('rename');
+    $this->assertIdentical($expected, $renames);
+
+    // Try to import the configuration. We expect an exception to be thrown
+    // because the staged entity is of a different type.
+    try {
+      $this->configImporter->import();
+      $this->fail('Expected ConfigImporterException thrown when a renamed configuration entity does not match the existing entity type.');
+    }
+    catch (ConfigImporterException $e) {
+      $this->pass('Expected ConfigImporterException thrown when a renamed configuration entity does not match the existing entity type.');
+      $expected = array(
+        String::format('Entity type mismatch on rename. !old_type not equal to !new_type for existing configuration !old_name and staged configuration !new_name.', array('old_type' => 'node_type', 'new_type' => 'config_test', 'old_name' => 'node.type.' . $content_type->id(), 'new_name' => 'config_test.dynamic.' . $test_entity_id))
+      );
+      $this->assertIdentical($expected, $this->configImporter->getErrors());
+    }
+  }
+
+}
