diff --git a/core/lib/Drupal/Core/Config/ConfigImporter.php b/core/lib/Drupal/Core/Config/ConfigImporter.php
index 2d0de14..837abc0 100644
--- a/core/lib/Drupal/Core/Config/ConfigImporter.php
+++ b/core/lib/Drupal/Core/Config/ConfigImporter.php
@@ -511,8 +511,6 @@ public function doSyncStep($sync_step, &$context) {
    *   If the configuration is already importing.
    */
   public function initialize() {
-    $this->createExtensionChangelist();
-
     // Ensure that the changes have been validated.
     $this->validate();
 
@@ -710,8 +708,10 @@ protected function getNextConfigurationOperation() {
    * @throws \Drupal\Core\Config\ConfigImporterException
    *   Exception thrown if the validate event logged any errors.
    */
-  protected function validate() {
+  public function validate() {
     if (!$this->validated) {
+      // Create the list of installs and uninstalls.
+      $this->createExtensionChangelist();
       // Validate renames.
       foreach ($this->getUnprocessedConfiguration('rename') as $name) {
         $names = $this->storageComparer->extractRenameNames($name);
diff --git a/core/modules/config/src/Form/ConfigSingleImportForm.php b/core/modules/config/src/Form/ConfigSingleImportForm.php
index 15f173d..8a6e3b7 100644
--- a/core/modules/config/src/Form/ConfigSingleImportForm.php
+++ b/core/modules/config/src/Form/ConfigSingleImportForm.php
@@ -8,12 +8,23 @@
 namespace Drupal\config\Form;
 
 use Drupal\Component\Serialization\Yaml;
+use Drupal\config\StorageOverrideWrapper;
+use Drupal\Core\Config\ConfigImporter;
+use Drupal\Core\Config\ConfigImporterException;
+use Drupal\Core\Config\ConfigManagerInterface;
+use Drupal\Core\Config\StorageComparer;
 use Drupal\Core\Config\StorageInterface;
+use Drupal\Core\Config\TypedConfigManagerInterface;
 use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Extension\ModuleInstallerInterface;
+use Drupal\Core\Extension\ThemeHandlerInterface;
 use Drupal\Core\Form\ConfirmFormBase;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Lock\LockBackendInterface;
 use Drupal\Core\Url;
 use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 
 /**
  * Provides a form for importing a single configuration file.
@@ -35,6 +46,56 @@ class ConfigSingleImportForm extends ConfirmFormBase {
   protected $configStorage;
 
   /**
+   * The database lock object.
+   *
+   * @var \Drupal\Core\Lock\LockBackendInterface
+   */
+  protected $lock;
+
+  /**
+   * Event dispatcher.
+   *
+   * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
+   */
+  protected $eventDispatcher;
+
+  /**
+   * The configuration manager.
+   *
+   * @var \Drupal\Core\Config\ConfigManagerInterface;
+   */
+  protected $configManager;
+
+  /**
+   * The typed config manager.
+   *
+   * @var \Drupal\Core\Config\TypedConfigManagerInterface
+   */
+  protected $typedConfigManager;
+
+  /**
+   * The module handler.
+   *
+   * @var \Drupal\Core\Extension\ModuleHandlerInterface
+   */
+  protected $moduleHandler;
+
+  /**
+   * The theme handler.
+   *
+   * @var \Drupal\Core\Extension\ThemeHandlerInterface
+   */
+  protected $themeHandler;
+
+  /**
+   * The module installer.
+   *
+   * @var \Drupal\Core\Extension\ModuleInstallerInterface
+   */
+  protected $moduleInstaller;
+
+
+  /**
    * If the config exists, this is that object. Otherwise, FALSE.
    *
    * @var \Drupal\Core\Config\Config|\Drupal\Core\Config\Entity\ConfigEntityInterface|bool
@@ -56,9 +117,16 @@ class ConfigSingleImportForm extends ConfirmFormBase {
    * @param \Drupal\Core\Config\StorageInterface $config_storage
    *   The config storage.
    */
-  public function __construct(EntityManagerInterface $entity_manager, StorageInterface $config_storage) {
+  public function __construct(EntityManagerInterface $entity_manager, StorageInterface $config_storage, LockBackendInterface $lock, EventDispatcherInterface $event_dispatcher, ConfigManagerInterface $config_manager, TypedConfigManagerInterface $typed_config, ModuleHandlerInterface $module_handler, ModuleInstallerInterface $module_installer, ThemeHandlerInterface $theme_handler) {
     $this->entityManager = $entity_manager;
     $this->configStorage = $config_storage;
+    $this->lock = $lock;
+    $this->eventDispatcher = $event_dispatcher;
+    $this->configManager = $config_manager;
+    $this->typedConfigManager = $typed_config;
+    $this->moduleHandler = $module_handler;
+    $this->moduleInstaller = $module_installer;
+    $this->themeHandler = $theme_handler;
   }
 
   /**
@@ -67,7 +135,14 @@ public function __construct(EntityManagerInterface $entity_manager, StorageInter
   public static function create(ContainerInterface $container) {
     return new static(
       $container->get('entity.manager'),
-      $container->get('config.storage')
+      $container->get('config.storage'),
+      $container->get('lock.persistent'),
+      $container->get('event_dispatcher'),
+      $container->get('config.manager'),
+      $container->get('config.typed'),
+      $container->get('module_handler'),
+      $container->get('module_installer'),
+      $container->get('theme_handler')
     );
   }
 
@@ -204,6 +279,8 @@ public function validateForm(array &$form, FormStateInterface $form_state) {
         $form_state->setErrorByName('import', $this->t('Missing ID key "@id_key" for this @entity_type import.', array('@id_key' => $id_key, '@entity_type' => $definition->getLabel())));
         return;
       }
+
+      $config_name = $definition->getConfigPrefix() . '.' . $data[$id_key];
       // If there is an existing entity, ensure matching ID and UUID.
       if ($entity = $entity_storage->load($data[$id_key])) {
         $this->configExists = $entity;
@@ -222,10 +299,52 @@ public function validateForm(array &$form, FormStateInterface $form_state) {
       }
     }
     else {
-      $config = $this->config($form_state->getValue('config_name'));
+      $config_name = $form_state->getValue('config_name');
+      $config = $this->config($config_name);
       $this->configExists = !$config->isNew() ? $config : FALSE;
     }
 
+    // Use ConfigImporter validation.
+    if (!$form_state->getErrors()) {
+      $source_storage = new StorageOverrideWrapper($this->configStorage);
+      $source_storage->override($config_name, $data);
+      $storage_comparer = new StorageComparer(
+        $source_storage,
+        $this->configStorage,
+        $this->configManager
+      );
+
+      if (!$storage_comparer->createChangelist()->hasChanges()) {
+        $form_state->setErrorByName('import', $this->t('There are no changes to import.'));
+      }
+      else {
+        $config_importer = new ConfigImporter(
+          $storage_comparer,
+          $this->eventDispatcher,
+          $this->configManager,
+          $this->lock,
+          $this->typedConfigManager,
+          $this->moduleHandler,
+          $this->moduleInstaller,
+          $this->themeHandler,
+          $this->getStringTranslation()
+        );
+
+        try {
+          $config_importer->validate();
+          $form_state->set('config_importer', $config_importer);
+        } catch (ConfigImporterException $e) {
+          // There are validation errors.
+          $item_list = array(
+            '#theme' => 'item_list',
+            '#items' => $config_importer->getErrors(),
+            '#title' => $this->t('The configuration cannot be imported because it failed validation for the following reasons:'),
+          );
+          $form_state->setErrorByName('import', drupal_render($item_list));
+        }
+      }
+    }
+
     // Store the decoded version of the submitted import.
     $form_state->setValueForElement($form['import'], $data);
   }
@@ -241,28 +360,89 @@ public function submitForm(array &$form, FormStateInterface $form_state) {
       return;
     }
 
-    // If a simple configuration file was added, set the data and save.
-    if ($this->data['config_type'] === 'system.simple') {
-      $this->configFactory()->getEditable($this->data['config_name'])->setData($this->data['import'])->save();
-      drupal_set_message($this->t('The %name configuration was imported.', array('%name' => $this->data['config_name'])));
+    /** @var \Drupal\Core\Config\ConfigImporter $config_importer */
+    $config_importer = $form_state->get('config_importer');
+    if ($config_importer->alreadyImporting()) {
+      drupal_set_message($this->t('Another request may be importing configuration already.'), 'error');
     }
-    // For a config entity, create an entity and save it.
-    else {
+    else{
       try {
-        $entity_storage = $this->entityManager->getStorage($this->data['config_type']);
-        if ($this->configExists) {
-          $entity = $entity_storage->updateFromStorageRecord($this->configExists, $this->data['import']);
+        $sync_steps = $config_importer->initialize();
+        $batch = array(
+          'operations' => array(),
+          'finished' => array(get_class($this), 'finishBatch'),
+          'title' => t('Importing configuration'),
+          'init_message' => t('Starting configuration import.'),
+          'progress_message' => t('Completed @current step of @total.'),
+          'error_message' => t('Configuration import has encountered an error.'),
+        );
+        foreach ($sync_steps as $sync_step) {
+          $batch['operations'][] = array(array(get_class($this), 'processBatch'), array($config_importer, $sync_step));
+        }
+
+        batch_set($batch);
+      }
+      catch (ConfigImporterException $e) {
+        // There are validation errors.
+        drupal_set_message($this->t('The configuration import failed for the following reasons:'), 'error');
+        foreach ($config_importer->getErrors() as $message) {
+          drupal_set_message($message, 'error');
         }
-        else {
-          $entity = $entity_storage->createFromStorageRecord($this->data['import']);
+      }
+    }
+  }
+
+  /**
+   * Processes the config import batch and persists the importer.
+   *
+   * @param \Drupal\Core\Config\ConfigImporter $config_importer
+   *   The batch config importer object to persist.
+   * @param string $sync_step
+   *   The synchronization step to do.
+   * @param $context
+   *   The batch context.
+   */
+  public static function processBatch(ConfigImporter $config_importer, $sync_step, &$context) {
+    if (!isset($context['sandbox']['config_importer'])) {
+      $context['sandbox']['config_importer'] = $config_importer;
+    }
+
+    $config_importer = $context['sandbox']['config_importer'];
+    $config_importer->doSyncStep($sync_step, $context);
+    if ($errors = $config_importer->getErrors()) {
+      if (!isset($context['results']['errors'])) {
+        $context['results']['errors'] = array();
+      }
+      $context['results']['errors'] += $errors;
+    }
+  }
+
+  /**
+   * Finish batch.
+   *
+   * This function is a static function to avoid serializing the ConfigSync
+   * object unnecessarily.
+   */
+  public static function finishBatch($success, $results, $operations) {
+    if ($success) {
+      if (!empty($results['errors'])) {
+        foreach ($results['errors'] as $error) {
+          drupal_set_message($error, 'error');
+          \Drupal::logger('config_sync')->error($error);
         }
-        $entity->save();
-        drupal_set_message($this->t('The @entity_type %label was imported.', array('@entity_type' => $entity->getEntityTypeId(), '%label' => $entity->label())));
+        drupal_set_message(\Drupal::translation()->translate('The configuration was imported with errors.'), 'warning');
       }
-      catch (\Exception $e) {
-        drupal_set_message($e->getMessage(), 'error');
+      else {
+        drupal_set_message(\Drupal::translation()->translate('The configuration was imported successfully.'));
       }
     }
+    else {
+      // An error occurred.
+      // $operations contains the operations that remained unprocessed.
+      $error_operation = reset($operations);
+      $message = \Drupal::translation()->translate('An error occurred while processing %error_operation with arguments: @arguments', array('%error_operation' => $error_operation[0], '@arguments' => print_r($error_operation[1], TRUE)));
+      drupal_set_message($message, 'error');
+    }
   }
 
 }
diff --git a/core/modules/config/src/StorageOverrideWrapper.php b/core/modules/config/src/StorageOverrideWrapper.php
new file mode 100644
index 0000000..c4fc49b
--- /dev/null
+++ b/core/modules/config/src/StorageOverrideWrapper.php
@@ -0,0 +1,187 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\config\StorageOverrideWrapper.
+ */
+
+namespace Drupal\config;
+
+use Drupal\Core\Config\StorageInterface;
+use Drupal\Core\DependencyInjection\DependencySerializationTrait;
+
+class StorageOverrideWrapper implements StorageInterface {
+  use DependencySerializationTrait;
+
+  /**
+   * The configuration storage to be cached.
+   *
+   * @var \Drupal\Core\Config\StorageInterface
+   */
+  protected $storage;
+
+  /**
+   *
+   * @var array
+   */
+  protected $overrideData = array();
+
+  /**
+   * The storage collection.
+   *
+   * @var string
+   */
+  protected $collection;
+
+  /**
+   * Constructs a new CachedStorage.
+   *
+   * @param \Drupal\Core\Config\StorageInterface $storage
+   *   A configuration storage to be cached.
+   */
+  public function __construct(StorageInterface $storage, $collection = StorageInterface::DEFAULT_COLLECTION) {
+    $this->storage = $storage;
+    $this->collection = $collection;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function exists($name) {
+    return isset($this->overrideData[$this->collection][$name]) || $this->storage->exists($name);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function read($name) {
+    if (isset($this->overrideData[$this->collection][$name])) {
+      return $this->overrideData[$this->collection][$name];
+    }
+    return $this->storage->read($name);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function readMultiple(array $names) {
+    $data = $this->storage->readMultiple(($names));
+    foreach ($names as $name) {
+      if (isset($this->overrideData[$this->collection][$name])) {
+        $data[$name] = $this->overrideData[$this->collection][$name];
+      }
+    }
+    return $data;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function write($name, array $data) {
+    if (isset($this->overrideData[$this->collection][$name])) {
+      unset($this->overrideData[$this->collection][$name]);
+    }
+    return $this->storage->write($name, $data);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function delete($name) {
+    if (isset($this->overrideData[$this->collection][$name])) {
+      unset($this->overrideData[$this->collection][$name]);
+    }
+    return $this->storage->delete($name);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function rename($name, $new_name) {
+    if (isset($this->overrideData[$this->collection][$name])) {
+      $this->overrideData[$this->collection][$new_name] = $this->overrideData[$this->collection][$name];
+      unset($this->overrideData[$this->collection][$name]);
+    }
+    return $this->rename($name, $new_name);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function encode($data) {
+    return $this->storage->encode($data);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function decode($raw) {
+    return $this->storage->decode($raw);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function listAll($prefix = '') {
+    $names = $this->storage->listAll($prefix);
+    $additional_names = [];
+    if ($prefix === '') {
+      $additional_names = array_keys($this->overrideData[$this->collection]);
+    }
+    else {
+      foreach (array_keys($this->overrideData[$this->collection]) as $name) {
+        if (strpos($name, $prefix) === 0) {
+          $additional_names[] = $name;
+        }
+      }
+    }
+    if (!empty($additional_names)) {
+      $names = array_unique(array_merge($names, $additional_names));
+    }
+    return $names;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function deleteAll($prefix = '') {
+    if ($prefix === '') {
+      $this->overrideData[$this->collection] = [];
+    }
+    else {
+      foreach (array_keys($this->overrideData[$this->collection]) as $name) {
+        if (strpos($name, $prefix) === 0) {
+          unset($this->overrideData[$this->collection][$name]);
+        }
+      }
+    }
+    return $this->storage->deleteAll($prefix);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function createCollection($collection) {
+    $this->collection = $collection;
+    return $this->storage->createCollection($collection);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getAllCollectionNames() {
+    return $this->storage->getAllCollectionNames();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getCollectionName() {
+    return $this->collection;
+  }
+
+  public function override($name, array $data) {
+    $this->overrideData[$this->collection][$name] = $data;
+    return $this;
+  }
+}
diff --git a/core/modules/config/src/Tests/ConfigSingleImportExportTest.php b/core/modules/config/src/Tests/ConfigSingleImportExportTest.php
index 7b3336d..2edf9d8 100644
--- a/core/modules/config/src/Tests/ConfigSingleImportExportTest.php
+++ b/core/modules/config/src/Tests/ConfigSingleImportExportTest.php
@@ -66,7 +66,7 @@ public function testImport() {
     $this->assertIdentical($entity->label(), 'First');
     $this->assertIdentical($entity->id(), 'first');
     $this->assertTrue($entity->status());
-    $this->assertRaw(t('The @entity_type %label was imported.', array('@entity_type' => 'config_test', '%label' => $entity->label())));
+    $this->assertRaw(t('The configuration was imported successfully.'));
 
     // Attempt an import with an existing ID but missing UUID.
     $this->drupalPostForm('admin/config/development/configuration/single/import', $edit, t('Import'));
@@ -82,8 +82,7 @@ public function testImport() {
     $this->drupalPostForm('admin/config/development/configuration/single/import', $edit, t('Import'));
     $this->assertRaw(t('Are you sure you want to create a new %name @type?', array('%name' => 'custom_id', '@type' => 'test configuration')));
     $this->drupalPostForm(NULL, array(), t('Confirm'));
-    $entity = $storage->load('custom_id');
-    $this->assertRaw(t('The @entity_type %label was imported.', array('@entity_type' => 'config_test', '%label' => $entity->label())));
+    $this->assertRaw(t('The configuration was imported successfully.'));
 
     // Perform an import with a unique ID and UUID.
     $import = <<<EOD
@@ -103,7 +102,7 @@ public function testImport() {
     $this->assertRaw(t('Are you sure you want to create a new %name @type?', array('%name' => 'second', '@type' => 'test configuration')));
     $this->drupalPostForm(NULL, array(), t('Confirm'));
     $entity = $storage->load('second');
-    $this->assertRaw(t('The @entity_type %label was imported.', array('@entity_type' => 'config_test', '%label' => $entity->label())));
+    $this->assertRaw(t('The configuration was imported successfully.'));
     $this->assertIdentical($entity->label(), 'Second');
     $this->assertIdentical($entity->id(), 'second');
     $this->assertFalse($entity->status());
@@ -126,7 +125,7 @@ public function testImport() {
     $this->assertRaw(t('Are you sure you want to update the %name @type?', array('%name' => 'second', '@type' => 'test configuration')));
     $this->drupalPostForm(NULL, array(), t('Confirm'));
     $entity = $storage->load('second');
-    $this->assertRaw(t('The @entity_type %label was imported.', array('@entity_type' => 'config_test', '%label' => $entity->label())));
+    $this->assertRaw(t('The configuration was imported successfully.'));
     $this->assertIdentical($entity->label(), 'Second updated');
   }
 
