diff --git a/core/lib/Drupal/Core/Config/ConfigImporter.php b/core/lib/Drupal/Core/Config/ConfigImporter.php
index 4f28425..9a4ebcd 100644
--- a/core/lib/Drupal/Core/Config/ConfigImporter.php
+++ b/core/lib/Drupal/Core/Config/ConfigImporter.php
@@ -240,11 +240,12 @@ public function getStorageComparer() {
    */
   public function reset() {
     $this->storageComparer->reset();
+    // Empty all the lists.
     foreach ($this->storageComparer->getAllCollectionNames() as $collection) {
       $this->processedConfiguration[$collection] = $this->storageComparer->getEmptyChangelist();
     }
-    $this->processedExtensions = $this->getEmptyExtensionsProcessedList();
-    $this->createExtensionChangelist();
+    $this->extensionChangelist = $this->processedExtensions = $this->getEmptyExtensionsProcessedList();
+
     $this->validated = FALSE;
     $this->processedSystemTheme = FALSE;
     return $this;
@@ -359,6 +360,9 @@ protected function setProcessedExtension($type, $op, $name) {
    * Populates the extension change list.
    */
   protected function createExtensionChangelist() {
+    // Create an empty changelist.
+    $this->extensionChangelist = $this->getEmptyExtensionsProcessedList();
+
     // Read the extensions information to determine changes.
     $current_extensions = $this->storageComparer->getTargetStorage()->read('core.extension');
     $new_extensions = $this->storageComparer->getSourceStorage()->read('core.extension');
@@ -396,7 +400,7 @@ protected function createExtensionChangelist() {
     //  0 1 actions
     // @todo Move this sorting functionality to the extension system.
     array_multisort(array_values($module_list), SORT_ASC, array_keys($module_list), SORT_DESC, $module_list);
-    $uninstall = array_intersect(array_keys($module_list), $uninstall);
+    $this->extensionChangelist['module']['uninstall'] = array_intersect(array_keys($module_list), $uninstall);
 
     // Determine which modules to install.
     $install = array_keys(array_diff_key($new_extensions['module'], $current_extensions['module']));
@@ -404,22 +408,19 @@ protected function createExtensionChangelist() {
     // (with dependencies installed first, and modules of the same weight sorted
     // in alphabetical order).
     $module_list = array_reverse($module_list);
-    $install = array_intersect(array_keys($module_list), $install);
+    $this->extensionChangelist['module']['install'] = array_intersect(array_keys($module_list), $install);
+    if ($missing_modules = array_diff($install, $this->extensionChangelist['module']['install'])) {
+      $this->logError($this->formatPlural(
+        count($missing_modules),
+        'Unable to install module %modules since it does not exist.',
+        'Unable to install modules %modules since they do not exist.',
+        array('%modules' => implode(', ',$missing_modules))
+      ));
+    }
 
     // Work out what themes to install and to uninstall.
-    $theme_install = array_keys(array_diff_key($new_extensions['theme'], $current_extensions['theme']));
-    $theme_uninstall = array_keys(array_diff_key($current_extensions['theme'], $new_extensions['theme']));
-
-    $this->extensionChangelist = array(
-      'module' => array(
-        'uninstall' => $uninstall,
-        'install' => $install,
-      ),
-      'theme' => array(
-        'install' => $theme_install,
-        'uninstall' => $theme_uninstall,
-      ),
-    );
+    $this->extensionChangelist['theme']['install'] = array_keys(array_diff_key($new_extensions['theme'], $current_extensions['theme']));
+    $this->extensionChangelist['theme']['uninstall'] = array_keys(array_diff_key($current_extensions['theme'], $new_extensions['theme']));
   }
 
   /**
@@ -434,7 +435,7 @@ protected function createExtensionChangelist() {
    * @return array
    *   An array of extension names.
    */
-  protected function getExtensionChangelist($type, $op = NULL) {
+  public function getExtensionChangelist($type, $op = NULL) {
     if ($op) {
       return $this->extensionChangelist[$type][$op];
     }
diff --git a/core/lib/Drupal/Core/EventSubscriber/ConfigImportSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/ConfigImportSubscriber.php
index f17d5bd..b13a5e8 100644
--- a/core/lib/Drupal/Core/EventSubscriber/ConfigImportSubscriber.php
+++ b/core/lib/Drupal/Core/EventSubscriber/ConfigImportSubscriber.php
@@ -8,6 +8,7 @@
 namespace Drupal\Core\EventSubscriber;
 
 use Drupal\Core\Config\Config;
+use Drupal\Core\Config\ConfigImporter;
 use Drupal\Core\Config\ConfigImporterEvent;
 use Drupal\Core\Config\ConfigImportValidateEventSubscriberBase;
 use Drupal\Core\Config\ConfigNameException;
@@ -37,6 +38,79 @@ public function onConfigImporterValidate(ConfigImporterEvent $event) {
         }
       }
     }
+    $config_importer = $event->getConfigImporter();
+    if ($config_importer->getStorageComparer()->getSourceStorage()->exists('core.extension')) {
+      // Modules are already validated in the ConfigImporter.
+      // @see \Drupal\Core\Config\ConfigImporter::createExtensionChangelist()
+      $this->validateThemeInstalls($config_importer);
+      $this->validateDependencies($config_importer);
+    }
+  }
+
+  /**
+   * Validates all themes being installed during a configuration import exist.
+   *
+   * @param ConfigImporter $config_importer
+   *   The configuration importer.
+   */
+  protected function validateThemeInstalls(ConfigImporter $config_importer) {
+    $themes = \Drupal::service('theme_handler')->rebuildThemeData();
+    foreach ($config_importer->getExtensionChangelist('theme', 'install') as $theme) {
+      if (!isset($themes[$theme])) {
+        $config_importer->logError($this->t('Unable to install theme %theme since it does not exist.', array('%theme' => $theme)));
+      }
+    }
+  }
+
+  /**
+   * Validates configuration being imported does not have unmet dependencies.
+   *
+   * @param ConfigImporter $config_importer
+   *   The configuration importer.
+   */
+  protected function validateDependencies(ConfigImporter $config_importer) {
+    $core_extension = $config_importer->getStorageComparer()->getSourceStorage()->read('core.extension');
+    $existing_dependencies = [
+      'config' => $config_importer->getStorageComparer()->getSourceStorage()->listAll(),
+      'module' => array_keys($core_extension['module']),
+      'theme' => array_keys($core_extension['theme']),
+    ];
+
+    // Validate the dependencies of all the configuration. We have to validate
+    // the entire tree because existing configuration might depend on
+    // configuration that is being deleted.
+    foreach ($config_importer->getStorageComparer()->getSourceStorage()->listAll() as $name) {
+      // Ensure that the config owner is installed. This checks all
+      // configuration including configuration entities.
+      list($owner,) = explode('.', $name, 2);
+      if ($owner !== 'core' && !isset($core_extension['module'][$owner]) && !isset($core_extension['theme'][$owner])) {
+        $config_importer->logError($this->t('Configuration %name depends on the %owner extension that will not be installed after import.', array('%name' => $name, '%owner' => $owner)));
+        continue;
+      }
+
+      // Configuration entities have dependencies which can be checked.
+      $data = $config_importer->getStorageComparer()->getSourceStorage()->read($name);
+      if (isset($data['dependencies']) && isset($data['uuid'])) {
+        $dependencies_to_check = array_intersect_key($data['dependencies'], array_flip(['module', 'theme', 'config']));
+        foreach ($dependencies_to_check as $type => $dependencies) {
+          $diffs = array_diff($dependencies, $existing_dependencies[$type]);
+          if (!empty($diffs)) {
+            switch ($type) {
+              case 'module':
+                $config_importer->logError($this->t('Configuration %name depends on a module that will not be installed after import.', array('%name' => $name)));
+                break;
+              case 'theme':
+                $config_importer->logError($this->t('Configuration %name depends on a theme that will not be installed after import.', array('%name' => $name)));
+                break;
+              case 'config':
+                $config_importer->logError($this->t('Configuration %name depends on configuration that will not exist after import.', array('%name' => $name)));
+                break;
+            }
+          }
+        }
+      }
+    }
+
   }
 
 }
diff --git a/core/modules/config/src/Tests/ConfigImporterTest.php b/core/modules/config/src/Tests/ConfigImporterTest.php
index ebd6378..e393f10 100644
--- a/core/modules/config/src/Tests/ConfigImporterTest.php
+++ b/core/modules/config/src/Tests/ConfigImporterTest.php
@@ -541,4 +541,51 @@ function testIsInstallable() {
     $this->assertTrue($this->container->get('config.storage')->exists($config_name));
   }
 
+  /**
+   * Tests dependency validation during configuration import.
+   *
+   * @see \Drupal\Core\EventSubscriber\ConfigImportSubscriber
+   * @see \Drupal\Core\Config\ConfigImporter::createExtensionChangelist()
+   */
+  public function testUnmetDependency() {
+    $staging = \Drupal::service('config.storage.staging');
+
+    // Test an unknown configuration owner.
+    $staging->write('unknown.config', ['test' => 'test']);
+
+    // Make a config entity have unmet dependencies.
+    $config_entity_data = $staging->read('config_test.dynamic.dotted.default');
+    $config_entity_data['dependencies'] = ['module' => ['unknown']];
+    $staging->write('config_test.dynamic.dotted.module', $config_entity_data);
+    $config_entity_data['dependencies'] = ['theme' => ['unknown']];
+    $staging->write('config_test.dynamic.dotted.theme', $config_entity_data);
+    $config_entity_data['dependencies'] = ['config' => ['unknown']];
+    $staging->write('config_test.dynamic.dotted.config', $config_entity_data);
+
+    // Add a module and a theme that do not exist.
+    $extensions = $staging->read('core.extension');
+    $extensions['module']['unknown_module'] = 0;
+    $extensions['theme']['unknown_theme'] = 0;
+    $staging->write('core.extension', $extensions);
+    try {
+      $this->configImporter->reset()->import();
+      $this->assertFalse(FALSE, 'ConfigImporterException not thrown, invalid import was not stopped due to missing dependencies.');
+    }
+    catch (ConfigImporterException $e) {
+      $this->assertEqual($e->getMessage(), 'There were errors validating the config synchronization.');
+      $error_log = $this->configImporter->getErrors();
+      $expected = [
+        'Unable to install module <em class="placeholder">unknown_module</em> since it does not exist.',
+        'Unable to install theme <em class="placeholder">unknown_theme</em> since it does not exist.',
+        'Configuration <em class="placeholder">config_test.dynamic.dotted.config</em> depends on configuration that will not exist after import.',
+        'Configuration <em class="placeholder">config_test.dynamic.dotted.module</em> depends on a module that will not be installed after import.',
+        'Configuration <em class="placeholder">config_test.dynamic.dotted.theme</em> depends on a theme that will not be installed after import.',
+        'Configuration <em class="placeholder">unknown.config</em> depends on the <em class="placeholder">unknown</em> extension that will not be installed after import.'
+      ];
+      foreach ($expected as $expected_message) {
+        $this->assertTrue(in_array($expected_message, $error_log), $expected_message);
+      }
+    }
+  }
+
 }
diff --git a/core/modules/field/src/Tests/FieldImportDeleteUninstallUiTest.php b/core/modules/field/src/Tests/FieldImportDeleteUninstallUiTest.php
index 53998e7..776c13b 100644
--- a/core/modules/field/src/Tests/FieldImportDeleteUninstallUiTest.php
+++ b/core/modules/field/src/Tests/FieldImportDeleteUninstallUiTest.php
@@ -99,6 +99,7 @@ public function testImportDeleteUninstall() {
     // fields.
     unset($core_extension['module']['text']);
     $staging->write('core.extension', $core_extension);
+    $staging->delete("text.settings");
     $this->drupalGet('admin/config/development/configuration');
     $this->assertText('This synchronization will delete data from the fields: entity_test.field_tel, entity_test.field_text.');
     // Delete all the text fields in staging, entity_test_install() adds quite
@@ -108,6 +109,7 @@ public function testImportDeleteUninstall() {
         if ($info['type'] == 'text') {
           $staging->delete("field.storage.$entity_type.$field_name");
           $staging->delete("field.field.$entity_type.$entity_type.$field_name");
+          $staging->delete("core.entity_form_display.$entity_type.$entity_type.default");
         }
       }
     }
diff --git a/core/modules/system/src/SystemConfigSubscriber.php b/core/modules/system/src/SystemConfigSubscriber.php
index 765b824..ed412a2 100644
--- a/core/modules/system/src/SystemConfigSubscriber.php
+++ b/core/modules/system/src/SystemConfigSubscriber.php
@@ -7,32 +7,58 @@
 
 namespace Drupal\system;
 
+use Drupal\Core\Config\ConfigEvents;
 use Drupal\Core\Config\ConfigImporterEvent;
-use Drupal\Core\Config\ConfigImportValidateEventSubscriberBase;
-use Drupal\Core\Config\StorageDispatcher;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
 
 /**
  * System Config subscriber.
  */
-class SystemConfigSubscriber extends ConfigImportValidateEventSubscriberBase {
+class SystemConfigSubscriber implements EventSubscriberInterface {
+  use StringTranslationTrait;
 
   /**
    * Checks that the configuration synchronization is valid.
    *
-   * This event listener implements two checks:
-   *   - prevents deleting all configuration.
-   *   - checks that the system.site:uuid's in the source and target match.
+   * This event listener prevents deleting all configuration. If there is
+   * nothing to import then event propagation is stopped because there is no
+   * config import to validate.
    *
    * @param ConfigImporterEvent $event
    *   The config import event.
    */
-  public function onConfigImporterValidate(ConfigImporterEvent $event) {
+  public function onConfigImporterValidateNotEmpty(ConfigImporterEvent $event) {
     $importList = $event->getConfigImporter()->getStorageComparer()->getSourceStorage()->listAll();
     if (empty($importList)) {
       $event->getConfigImporter()->logError($this->t('This import is empty and if applied would delete all of your configuration, so has been rejected.'));
+      $event->stopPropagation();
     }
+  }
+
+  /**
+   * Checks that the configuration synchronization is valid.
+   *
+   * This event listener checks that the system.site:uuid's in the source and
+   * target match.
+   *
+   * @param ConfigImporterEvent $event
+   *   The config import event.
+   */
+  public function onConfigImporterValidateSiteUUID(ConfigImporterEvent $event) {
     if (!$event->getConfigImporter()->getStorageComparer()->validateSiteUuid()) {
       $event->getConfigImporter()->logError($this->t('Site UUID in source storage does not match the target storage.'));
     }
   }
+
+  /**
+   * {@inheritdoc}
+   */
+  static function getSubscribedEvents() {
+    // The empty check has a high priority so that is can stop propagation if
+    // there is no configuration to import.
+    $events[ConfigEvents::IMPORT_VALIDATE][] = array('onConfigImporterValidateNotEmpty', 512);
+    $events[ConfigEvents::IMPORT_VALIDATE][] = array('onConfigImporterValidateSiteUUID', 256);
+    return $events;
+  }
 }
