diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php
index e5d943c..dd6481e 100644
--- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php
+++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php
@@ -278,8 +278,9 @@ public function preSave(EntityStorageInterface $storage) {
       throw new ConfigDuplicateUUIDException(String::format('Attempt to save a configuration entity %id with UUID %uuid when this UUID is already used for %matched', array('%id' => $this->id(), '%uuid' => $this->uuid(), '%matched' => $matched_entity)));
     }
 
+    // If this entity is not new, load the original entity for comparison.
     if (!$this->isNew()) {
-      $original = $storage->loadUnchanged($this->id());
+      $original = $storage->loadUnchanged($this->getOriginalId());
       // Ensure that the UUID cannot be changed for an existing entity.
       if ($original && ($original->uuid() != $this->uuid())) {
         throw new ConfigDuplicateUUIDException(String::format('Attempt to save a configuration entity %id with UUID %uuid when this entity already exists with UUID %original_uuid', array('%id' => $this->id(), '%uuid' => $this->uuid(), '%original_uuid' => $original->uuid())));
diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php
index 4656897..2703632 100644
--- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php
+++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php
@@ -18,6 +18,7 @@
 use Drupal\Core\Entity\EntityStorageException;
 use Drupal\Core\Entity\Query\QueryFactory;
 use Drupal\Component\Uuid\UuidInterface;
+use Drupal\Core\Language\LanguageManagerInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -66,6 +67,13 @@ class ConfigEntityStorage extends EntityStorageBase implements ConfigEntityStora
   protected $configStorage;
 
   /**
+   * The language manager.
+   *
+   * @var \Drupal\Core\Language\LanguageManagerInterface
+   */
+  protected $languageManager;
+
+  /**
    * Constructs a ConfigEntityStorage object.
    *
    * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
@@ -76,8 +84,10 @@ class ConfigEntityStorage extends EntityStorageBase implements ConfigEntityStora
    *   The config storage service.
    * @param \Drupal\Component\Uuid\UuidInterface $uuid_service
    *   The UUID service.
+   * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
+   *   The language manager.
    */
-  public function __construct(EntityTypeInterface $entity_type, ConfigFactoryInterface $config_factory, StorageInterface $config_storage, UuidInterface $uuid_service) {
+  public function __construct(EntityTypeInterface $entity_type, ConfigFactoryInterface $config_factory, StorageInterface $config_storage, UuidInterface $uuid_service, LanguageManagerInterface $language_manager) {
     parent::__construct($entity_type);
 
     $this->idKey = $this->entityType->getKey('id');
@@ -86,6 +96,7 @@ public function __construct(EntityTypeInterface $entity_type, ConfigFactoryInter
     $this->configFactory = $config_factory;
     $this->configStorage = $config_storage;
     $this->uuidService = $uuid_service;
+    $this->languageManager = $language_manager;
   }
 
   /**
@@ -96,7 +107,8 @@ public static function createInstance(ContainerInterface $container, EntityTypeI
       $entity_type,
       $container->get('config.factory'),
       $container->get('config.storage'),
-      $container->get('uuid')
+      $container->get('uuid'),
+      $container->get('language_manager')
     );
   }
 
@@ -228,7 +240,7 @@ public function create(array $values = array()) {
     $class::preCreate($this, $values);
 
     // Set default language to site default if not provided.
-    $values += array('langcode' => language_default()->id);
+    $values += array('langcode' => $this->languageManager->getDefaultLanguage()->id);
 
     $entity = new $class($values, $this->entityTypeId);
     // Mark this entity as new, so isNew() returns TRUE. This does not check
@@ -336,9 +348,6 @@ public function save(EntityInterface $entity) {
       $config->save();
       $entity->postSave($this, TRUE);
       $this->invokeHook('update', $entity);
-
-      // Immediately update the original ID.
-      $entity->setOriginalId($entity->id());
     }
     else {
       $return = SAVED_NEW;
@@ -348,6 +357,11 @@ public function save(EntityInterface $entity) {
       $this->invokeHook('insert', $entity);
     }
 
+    // After saving, this is now the "original entity", and subsequent saves
+    // will be updates instead of inserts, and updates must always be able to
+    // correctly identify the original entity.
+    $entity->setOriginalId($entity->id());
+
     unset($entity->original);
 
     return $return;
diff --git a/core/lib/Drupal/Core/Entity/Entity.php b/core/lib/Drupal/Core/Entity/Entity.php
index e56bb65..5e43af3 100644
--- a/core/lib/Drupal/Core/Entity/Entity.php
+++ b/core/lib/Drupal/Core/Entity/Entity.php
@@ -313,7 +313,9 @@ public function delete() {
   public function createDuplicate() {
     $duplicate = clone $this;
     $entity_type = $this->getEntityType();
+    // Reset the entity ID and indicate that this is a new entity.
     $duplicate->{$entity_type->getKey('id')} = NULL;
+    $duplicate->enforceIsNew();
 
     // Check if the entity type supports UUIDs and generate a new one if so.
     if ($entity_type->hasKey('uuid')) {
diff --git a/core/modules/breakpoint/lib/Drupal/breakpoint/Entity/Breakpoint.php b/core/modules/breakpoint/lib/Drupal/breakpoint/Entity/Breakpoint.php
index e200894..5fa0260 100644
--- a/core/modules/breakpoint/lib/Drupal/breakpoint/Entity/Breakpoint.php
+++ b/core/modules/breakpoint/lib/Drupal/breakpoint/Entity/Breakpoint.php
@@ -106,6 +106,18 @@ class Breakpoint extends ConfigEntityBase implements BreakpointInterface {
   public $multipliers = array();
 
   /**
+   * {@inheritdoc}
+   */
+  public function id() {
+    // If no ID is specified, build one from the properties that uniquely define
+    // this breakpoint.
+    if (!isset($this->id)) {
+      $this->id = $this->sourceType . '.' . $this->source . '.' . $this->name;
+    }
+    return $this->id;
+  }
+
+  /**
    * Overrides Drupal\config\ConfigEntityBase::save().
    */
   public function save() {
@@ -114,13 +126,6 @@ public function save() {
       throw new InvalidBreakpointException('Invalid data detected.');
     }
 
-    // Build an id if none is set.
-    // Since a particular name can be used by multiple theme/modules we need
-    // to make a unique id.
-    if (empty($this->id)) {
-      $this->id = $this->sourceType . '.' . $this->source . '.' . $this->name;
-    }
-
     // Set the label if none is set.
     if (empty($this->label)) {
       $this->label = $this->name;
diff --git a/core/modules/breakpoint/lib/Drupal/breakpoint/Entity/BreakpointGroup.php b/core/modules/breakpoint/lib/Drupal/breakpoint/Entity/BreakpointGroup.php
index 9840657d..595ca76 100644
--- a/core/modules/breakpoint/lib/Drupal/breakpoint/Entity/BreakpointGroup.php
+++ b/core/modules/breakpoint/lib/Drupal/breakpoint/Entity/BreakpointGroup.php
@@ -104,15 +104,24 @@ public function save() {
     if (!$this->isValid()) {
       throw new InvalidBreakpointException('Invalid data detected.');
     }
-    if (empty($this->id)) {
-      $this->id = $this->sourceType . '.' . $this->source . '.' . $this->name;
-    }
     parent::save();
   }
 
   /**
    * {@inheritdoc}
    */
+  public function id() {
+    // If no ID is specified, build one from the properties that uniquely define
+    // this breakpoint group.
+    if (!isset($this->id)) {
+      $this->id = $this->sourceType . '.' . $this->source . '.' . $this->name;
+    }
+    return $this->id;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function isValid() {
     // Check for illegal values in breakpoint group source type.
     if (!in_array($this->sourceType, array(
diff --git a/core/modules/breakpoint/lib/Drupal/breakpoint/Tests/BreakpointAPITest.php b/core/modules/breakpoint/lib/Drupal/breakpoint/Tests/BreakpointAPITest.php
index 85d0711..e132280 100644
--- a/core/modules/breakpoint/lib/Drupal/breakpoint/Tests/BreakpointAPITest.php
+++ b/core/modules/breakpoint/lib/Drupal/breakpoint/Tests/BreakpointAPITest.php
@@ -46,7 +46,7 @@ public function testConfigName() {
     $this->assertTrue($exception, 'breakpoint_config_name: An exception is thrown when an invalid sourceType is entered.');
 
     // Try an invalid source.
-    $breakpoint->id = '';
+    $breakpoint = $breakpoint->createDuplicate();
     $breakpoint->sourceType = Breakpoint::SOURCE_TYPE_USER_DEFINED;
     $breakpoint->source = 'custom*_module source';
 
@@ -60,7 +60,7 @@ public function testConfigName() {
     $this->assertTrue($exception, 'breakpoint_config_name: An exception is thrown when an invalid source is entered.');
 
     // Try an invalid name (make sure there is at least once capital letter).
-    $breakpoint->id = '';
+    $breakpoint = $breakpoint->createDuplicate();
     $breakpoint->source = 'custom_module';
     $breakpoint->name = drupal_ucfirst($this->randomName());
 
@@ -74,7 +74,7 @@ public function testConfigName() {
     $this->assertTrue($exception, 'breakpoint_config_name: An exception is thrown when an invalid name is entered.');
 
     // Try a valid breakpoint.
-    $breakpoint->id = '';
+    $breakpoint = $breakpoint->createDuplicate();
     $breakpoint->name = drupal_strtolower($this->randomName());
     $breakpoint->mediaQuery = 'all';
 
diff --git a/core/modules/breakpoint/lib/Drupal/breakpoint/Tests/BreakpointGroupAPITest.php b/core/modules/breakpoint/lib/Drupal/breakpoint/Tests/BreakpointGroupAPITest.php
index 3751c81..7a563f6 100644
--- a/core/modules/breakpoint/lib/Drupal/breakpoint/Tests/BreakpointGroupAPITest.php
+++ b/core/modules/breakpoint/lib/Drupal/breakpoint/Tests/BreakpointGroupAPITest.php
@@ -49,6 +49,7 @@ public function testConfigName() {
     $this->assertTrue($exception, 'An exception is thrown when an invalid sourceType is entered.');
 
     // Try an invalid source.
+    $breakpoint_group = $breakpoint_group->createDuplicate();
     $breakpoint_group->name = '';
     $breakpoint_group->sourceType = Breakpoint::SOURCE_TYPE_USER_DEFINED;
     $breakpoint_group->source = 'custom*_module source';
@@ -63,6 +64,7 @@ public function testConfigName() {
     $this->assertTrue($exception, 'An exception is thrown when an invalid source is entered.');
 
     // Try a valid breakpoint_group.
+    $breakpoint_group = $breakpoint_group->createDuplicate();
     $breakpoint_group->name = 'test';
     $breakpoint_group->source = 'custom_module_source';
 
diff --git a/core/modules/field/lib/Drupal/field/FieldConfigStorage.php b/core/modules/field/lib/Drupal/field/FieldConfigStorage.php
index ba1803a..66951c2 100644
--- a/core/modules/field/lib/Drupal/field/FieldConfigStorage.php
+++ b/core/modules/field/lib/Drupal/field/FieldConfigStorage.php
@@ -13,6 +13,7 @@
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Entity\Query\QueryFactory;
+use Drupal\Core\Language\LanguageManagerInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Config\StorageInterface;
@@ -56,6 +57,8 @@ class FieldConfigStorage extends ConfigEntityStorage {
    *   The config storage service.
    * @param \Drupal\Component\Uuid\UuidInterface $uuid_service
    *   The UUID service.
+   * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
+   *   The language manager.
    * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
    *   The entity manager.
    * @param \Drupal\Core\Extension\ModuleHandler $module_handler
@@ -63,8 +66,8 @@ class FieldConfigStorage extends ConfigEntityStorage {
    * @param \Drupal\Core\KeyValueStore\StateInterface $state
    *   The state key value store.
    */
-  public function __construct(EntityTypeInterface $entity_type, ConfigFactoryInterface $config_factory, StorageInterface $config_storage, UuidInterface $uuid_service, EntityManagerInterface $entity_manager, ModuleHandler $module_handler, StateInterface $state) {
-    parent::__construct($entity_type, $config_factory, $config_storage, $uuid_service);
+  public function __construct(EntityTypeInterface $entity_type, ConfigFactoryInterface $config_factory, StorageInterface $config_storage, UuidInterface $uuid_service, LanguageManagerInterface $language_manager, EntityManagerInterface $entity_manager, ModuleHandler $module_handler, StateInterface $state) {
+    parent::__construct($entity_type, $config_factory, $config_storage, $uuid_service, $language_manager);
     $this->entityManager = $entity_manager;
     $this->moduleHandler = $module_handler;
     $this->state = $state;
@@ -79,6 +82,7 @@ public static function createInstance(ContainerInterface $container, EntityTypeI
       $container->get('config.factory'),
       $container->get('config.storage'),
       $container->get('uuid'),
+      $container->get('language_manager'),
       $container->get('entity.manager'),
       $container->get('module_handler'),
       $container->get('state')
diff --git a/core/modules/field/lib/Drupal/field/FieldInstanceConfigStorage.php b/core/modules/field/lib/Drupal/field/FieldInstanceConfigStorage.php
index 1942ef5..9d9826a 100644
--- a/core/modules/field/lib/Drupal/field/FieldInstanceConfigStorage.php
+++ b/core/modules/field/lib/Drupal/field/FieldInstanceConfigStorage.php
@@ -12,6 +12,7 @@
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Entity\Query\QueryFactory;
+use Drupal\Core\Language\LanguageManagerInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Component\Uuid\UuidInterface;
@@ -54,13 +55,15 @@ class FieldInstanceConfigStorage extends ConfigEntityStorage {
    *   The config storage service.
    * @param \Drupal\Component\Uuid\UuidInterface $uuid_service
    *   The UUID service.
+   * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
+   *   The language manager.
    * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
    *   The entity manager.
    * @param \Drupal\Core\KeyValueStore\StateInterface $state
    *   The state key value store.
    */
-  public function __construct(EntityTypeInterface $entity_type, ConfigFactoryInterface $config_factory, StorageInterface $config_storage, UuidInterface $uuid_service, EntityManagerInterface $entity_manager, StateInterface $state) {
-    parent::__construct($entity_type, $config_factory, $config_storage, $uuid_service);
+  public function __construct(EntityTypeInterface $entity_type, ConfigFactoryInterface $config_factory, StorageInterface $config_storage, UuidInterface $uuid_service, LanguageManagerInterface $language_manager, EntityManagerInterface $entity_manager, StateInterface $state) {
+    parent::__construct($entity_type, $config_factory, $config_storage, $uuid_service, $language_manager);
     $this->entityManager = $entity_manager;
     $this->state = $state;
   }
@@ -74,6 +77,7 @@ public static function createInstance(ContainerInterface $container, EntityTypeI
       $container->get('config.factory'),
       $container->get('config.storage'),
       $container->get('uuid'),
+      $container->get('language_manager'),
       $container->get('entity.manager'),
       $container->get('state')
     );
diff --git a/core/modules/filter/lib/Drupal/filter/Tests/FilterCrudTest.php b/core/modules/filter/lib/Drupal/filter/Tests/FilterCrudTest.php
index 8320336..a645691 100644
--- a/core/modules/filter/lib/Drupal/filter/Tests/FilterCrudTest.php
+++ b/core/modules/filter/lib/Drupal/filter/Tests/FilterCrudTest.php
@@ -41,9 +41,10 @@ function testTextFormatCrud() {
     $this->verifyTextFormat($format);
 
     // Add another text format specifying all possible properties.
-    $format = entity_create('filter_format');
-    $format->format = 'custom_format';
-    $format->name = 'Custom format';
+    $format = entity_create('filter_format', array(
+      'format' => 'custom_format',
+      'name' => 'Custom format',
+    ));
     $format->setFilterConfig('filter_url', array(
       'status' => 1,
       'settings' => array(
diff --git a/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityBaseUnitTest.php b/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityBaseUnitTest.php
index dcdfb76..a23f032 100644
--- a/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityBaseUnitTest.php
+++ b/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityBaseUnitTest.php
@@ -369,6 +369,8 @@ public function testCreateDuplicate() {
     $duplicate = $this->entity->createDuplicate();
     $this->assertInstanceOf('\Drupal\Core\Entity\Entity', $duplicate);
     $this->assertNotSame($this->entity, $duplicate);
+    $this->assertFalse($this->entity->isNew());
+    $this->assertTrue($duplicate->isNew());
     $this->assertNull($duplicate->id());
     $this->assertNull($duplicate->getOriginalId());
     $this->assertNotEquals($this->entity->uuid(), $duplicate->uuid());
diff --git a/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityStorageTest.php b/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityStorageTest.php
new file mode 100644
index 0000000..918e596
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityStorageTest.php
@@ -0,0 +1,723 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\Core\Config\Entity\ConfigEntityStorageTest.
+ */
+
+namespace Drupal\Tests\Core\Config\Entity {
+
+use Drupal\Core\Config\Entity\ConfigEntityInterface;
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Language\Language;
+use Drupal\Tests\UnitTestCase;
+
+/**
+ * @coversDefaultClass \Drupal\Core\Config\Entity\ConfigEntityStorage
+ *
+ * @group Drupal
+ */
+class ConfigEntityStorageTest extends UnitTestCase {
+
+  /**
+   * The entity type.
+   *
+   * @var \Drupal\Core\Entity\EntityTypeInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $entityType;
+
+  /**
+   * The module handler.
+   *
+   * @var \Drupal\Core\Extension\ModuleHandlerInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $moduleHandler;
+
+  /**
+   * The UUID service.
+   *
+   * @var \Drupal\Component\Uuid\UuidInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $uuidService;
+
+  /**
+   * The language manager.
+   *
+   * @var \Drupal\Core\Language\LanguageManagerInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $languageManager;
+
+  /**
+   * The config storage controller.
+   *
+   * @var \Drupal\Core\Config\Entity\ConfigEntityStorage
+   */
+  protected $entityStorage;
+
+  /**
+   * The config factory service.
+   *
+   * @var \Drupal\Core\Config\ConfigFactoryInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $configFactory;
+
+  /**
+   * The config storage service.
+   *
+   * @var \Drupal\Core\Config\StorageInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $configStorage;
+
+  /**
+   * The entity query.
+   *
+   * @var \Drupal\Core\Entity\Query\QueryInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $entityQuery;
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'ConfigEntityStorage unit test',
+      'description' => 'Tests \Drupal\Core\Config\Entity\ConfigEntityStorage',
+      'group' => 'Configuration',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    $this->entityType = $this->getMock('Drupal\Core\Entity\EntityTypeInterface');
+    $this->entityType->expects($this->any())
+      ->method('getKey')
+      ->will($this->returnValueMap(array(
+        array('id', 'id'),
+        array('uuid', 'uuid'),
+      )));
+    $this->entityType->expects($this->any())
+      ->method('id')
+      ->will($this->returnValue('test_entity_type'));
+    $this->entityType->expects($this->any())
+      ->method('getConfigPrefix')
+      ->will($this->returnValue('the_config_prefix'));
+
+    $this->moduleHandler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface');
+
+    $this->uuidService = $this->getMock('Drupal\Component\Uuid\UuidInterface');
+
+    $this->languageManager = $this->getMock('Drupal\Core\Language\LanguageManagerInterface');
+    $this->languageManager->expects($this->any())
+      ->method('getDefaultLanguage')
+      ->will($this->returnValue(new Language(array('langcode' => 'en'))));
+
+    $this->configStorage = $this->getConfigStorageStub(array());
+
+    $this->configFactory = $this->getMock('Drupal\Core\Config\ConfigFactoryInterface');
+
+    $this->entityQuery = $this->getMock('Drupal\Core\Entity\Query\QueryInterface');
+
+    $this->entityStorage = $this->getMockBuilder('Drupal\Core\Config\Entity\ConfigEntityStorage')
+      ->setConstructorArgs(array($this->entityType, $this->configFactory, $this->configStorage, $this->uuidService, $this->languageManager))
+      ->setMethods(array('getQuery'))
+      ->getMock();
+    $this->entityStorage->expects($this->any())
+      ->method('getQuery')
+      ->will($this->returnValue($this->entityQuery));
+    $this->entityStorage->setModuleHandler($this->moduleHandler);
+  }
+
+  /**
+   * @covers ::create()
+   */
+  public function testCreateWithPredefinedUuid() {
+    $this->entityType->expects($this->atLeastOnce())
+      ->method('getClass')
+      ->will($this->returnValue(get_class($this->getMockEntity())));
+
+    $this->moduleHandler->expects($this->at(0))
+      ->method('invokeAll')
+      ->with('test_entity_type_create');
+    $this->moduleHandler->expects($this->at(1))
+      ->method('invokeAll')
+      ->with('entity_create');
+    $this->uuidService->expects($this->never())
+      ->method('generate');
+
+    $entity = $this->entityStorage->create(array('id' => 'foo', 'uuid' => 'baz'));
+    $this->assertInstanceOf('Drupal\Core\Entity\EntityInterface', $entity);
+    $this->assertSame('foo', $entity->id());
+    $this->assertSame('baz', $entity->uuid());
+  }
+
+  /**
+   * @covers ::create()
+   *
+   * @return \Drupal\Core\Entity\EntityInterface
+   */
+  public function testCreate() {
+    $this->entityType->expects($this->atLeastOnce())
+      ->method('getClass')
+      ->will($this->returnValue(get_class($this->getMockEntity())));
+
+    $this->moduleHandler->expects($this->at(0))
+      ->method('invokeAll')
+      ->with('test_entity_type_create');
+    $this->moduleHandler->expects($this->at(1))
+      ->method('invokeAll')
+      ->with('entity_create');
+    $this->uuidService->expects($this->once())
+      ->method('generate')
+      ->will($this->returnValue('bar'));
+
+    $entity = $this->entityStorage->create(array('id' => 'foo'));
+    $this->assertInstanceOf('Drupal\Core\Entity\EntityInterface', $entity);
+    $this->assertSame('foo', $entity->id());
+    $this->assertSame('bar', $entity->uuid());
+    return $entity;
+  }
+
+  /**
+   * @covers ::save()
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *
+   * @return \Drupal\Core\Entity\EntityInterface
+   *
+   * @depends testCreate
+   */
+  public function testSaveInsert(EntityInterface $entity) {
+    $config_object = $this->getMockBuilder('Drupal\Core\Config\Config')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $config_object->expects($this->atLeastOnce())
+      ->method('isNew')
+      ->will($this->returnValue(TRUE));
+    $config_object->expects($this->exactly(4))
+      ->method('set');
+    $config_object->expects($this->once())
+      ->method('save');
+
+    $this->configFactory->expects($this->once())
+      ->method('get')
+      ->with('the_config_prefix.foo')
+      ->will($this->returnValue($config_object));
+
+    $this->moduleHandler->expects($this->at(0))
+      ->method('invokeAll')
+      ->with('test_entity_type_presave');
+    $this->moduleHandler->expects($this->at(1))
+      ->method('invokeAll')
+      ->with('entity_presave');
+    $this->moduleHandler->expects($this->at(2))
+      ->method('invokeAll')
+      ->with('test_entity_type_insert');
+    $this->moduleHandler->expects($this->at(3))
+      ->method('invokeAll')
+      ->with('entity_insert');
+
+    $this->entityQuery->expects($this->once())
+      ->method('condition')
+      ->with('uuid', 'bar')
+      ->will($this->returnSelf());
+    $this->entityQuery->expects($this->once())
+      ->method('execute')
+      ->will($this->returnValue(array()));
+
+    $return = $this->entityStorage->save($entity);
+    $this->assertSame(SAVED_NEW, $return);
+    return $entity;
+  }
+
+  /**
+   * @covers ::save()
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *
+   * @return \Drupal\Core\Entity\EntityInterface
+   *
+   * @depends testSaveInsert
+   */
+  public function testSaveUpdate(EntityInterface $entity) {
+    $config_object = $this->getMockBuilder('Drupal\Core\Config\Config')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $config_object->expects($this->atLeastOnce())
+      ->method('isNew')
+      ->will($this->returnValue(FALSE));
+    $config_object->expects($this->exactly(4))
+      ->method('set');
+    $config_object->expects($this->once())
+      ->method('save');
+
+    $this->configFactory->expects($this->exactly(2))
+      ->method('loadMultiple')
+      ->with(array('the_config_prefix.foo'))
+      ->will($this->returnValue(array()));
+    $this->configFactory->expects($this->once())
+      ->method('get')
+      ->with('the_config_prefix.foo')
+      ->will($this->returnValue($config_object));
+
+    $this->moduleHandler->expects($this->at(0))
+      ->method('invokeAll')
+      ->with('test_entity_type_presave');
+    $this->moduleHandler->expects($this->at(1))
+      ->method('invokeAll')
+      ->with('entity_presave');
+    $this->moduleHandler->expects($this->at(2))
+      ->method('invokeAll')
+      ->with('test_entity_type_update');
+    $this->moduleHandler->expects($this->at(3))
+      ->method('invokeAll')
+      ->with('entity_update');
+
+    $this->entityQuery->expects($this->once())
+      ->method('condition')
+      ->with('uuid', 'bar')
+      ->will($this->returnSelf());
+    $this->entityQuery->expects($this->once())
+      ->method('execute')
+      ->will($this->returnValue(array($entity->id())));
+
+    $return = $this->entityStorage->save($entity);
+    $this->assertSame(SAVED_UPDATED, $return);
+    return $entity;
+  }
+
+  /**
+   * @covers ::save()
+   *
+   * @depends testSaveInsert
+   */
+  public function testSaveRename(ConfigEntityInterface $entity) {
+    $config_object = $this->getMockBuilder('Drupal\Core\Config\Config')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $config_object->expects($this->atLeastOnce())
+      ->method('isNew')
+      ->will($this->returnValue(FALSE));
+    $config_object->expects($this->exactly(4))
+      ->method('set');
+    $config_object->expects($this->once())
+      ->method('save');
+
+    $this->configFactory->expects($this->once())
+      ->method('rename')
+      ->will($this->returnValue($config_object));
+    $this->configFactory->expects($this->exactly(2))
+      ->method('loadMultiple')
+      ->with(array('the_config_prefix.foo'))
+      ->will($this->returnValue(array()));
+    $this->configFactory->expects($this->once())
+      ->method('get')
+      ->with('the_config_prefix.foo')
+      ->will($this->returnValue($config_object));
+
+    // Performing a rename does not change the original ID until saving.
+    $this->assertSame('foo', $entity->getOriginalId());
+    $entity->set('id', 'bar');
+    $this->assertSame('foo', $entity->getOriginalId());
+
+    $this->entityQuery->expects($this->once())
+      ->method('condition')
+      ->with('uuid', 'bar')
+      ->will($this->returnSelf());
+    $this->entityQuery->expects($this->once())
+      ->method('execute')
+      ->will($this->returnValue(array($entity->id())));
+
+    $return = $this->entityStorage->save($entity);
+    $this->assertSame(SAVED_UPDATED, $return);
+    $this->assertSame('bar', $entity->getOriginalId());
+  }
+
+  /**
+   * @covers ::save()
+   *
+   * @expectedException \Drupal\Core\Entity\EntityMalformedException
+   * @expectedExceptionMessage The entity does not have an ID.
+   */
+  public function testSaveInvalid() {
+    $entity = $this->getMockEntity();
+    $this->entityStorage->save($entity);
+  }
+
+  /**
+   * @covers ::save()
+   *
+   * @expectedException \Drupal\Core\Entity\EntityStorageException
+   */
+  public function testSaveDuplicate() {
+    $config_object = $this->getMockBuilder('Drupal\Core\Config\Config')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $config_object->expects($this->atLeastOnce())
+      ->method('isNew')
+      ->will($this->returnValue(FALSE));
+    $config_object->expects($this->never())
+      ->method('set');
+    $config_object->expects($this->never())
+      ->method('save');
+
+    $this->configFactory->expects($this->once())
+      ->method('get')
+      ->with('the_config_prefix.foo')
+      ->will($this->returnValue($config_object));
+
+    $entity = $this->getMockEntity(array('id' => 'foo'));
+    $entity->enforceIsNew();
+
+    $this->entityStorage->save($entity);
+  }
+
+  /**
+   * @covers ::save()
+   *
+   * @expectedException \Drupal\Core\Config\ConfigDuplicateUUIDException
+   * @expectedExceptionMessage when this UUID is already used for
+   */
+  public function testSaveMismatch() {
+    $config_object = $this->getMockBuilder('Drupal\Core\Config\Config')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $config_object->expects($this->atLeastOnce())
+      ->method('isNew')
+      ->will($this->returnValue(TRUE));
+    $config_object->expects($this->never())
+      ->method('save');
+
+    $this->configFactory->expects($this->once())
+      ->method('get')
+      ->with('the_config_prefix.foo')
+      ->will($this->returnValue($config_object));
+
+    $this->entityQuery->expects($this->once())
+      ->method('condition')
+      ->will($this->returnSelf());
+    $this->entityQuery->expects($this->once())
+      ->method('execute')
+      ->will($this->returnValue(array('baz')));
+
+    $entity = $this->getMockEntity(array('id' => 'foo'));
+    $this->entityStorage->save($entity);
+  }
+
+  /**
+   * @covers ::save()
+   */
+  public function testSaveNoMismatch() {
+    $config_object = $this->getMockBuilder('Drupal\Core\Config\Config')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $config_object->expects($this->atLeastOnce())
+      ->method('isNew')
+      ->will($this->returnValue(TRUE));
+    $config_object->expects($this->once())
+      ->method('save');
+
+    $this->configFactory->expects($this->once())
+      ->method('get')
+      ->with('the_config_prefix.baz')
+      ->will($this->returnValue($config_object));
+    $this->configFactory->expects($this->once())
+      ->method('rename')
+      ->will($this->returnValue($config_object));
+
+    $this->entityQuery->expects($this->once())
+      ->method('condition')
+      ->will($this->returnSelf());
+    $this->entityQuery->expects($this->once())
+      ->method('execute')
+      ->will($this->returnValue(array('baz')));
+
+    $entity = $this->getMockEntity(array('id' => 'foo'));
+    $entity->enforceIsNew();
+    $entity->setOriginalId('baz');
+    $this->entityStorage->save($entity);
+  }
+
+  /**
+   * @covers ::save()
+   *
+   * @expectedException \Drupal\Core\Config\ConfigDuplicateUUIDException
+   * @expectedExceptionMessage when this entity already exists with UUID
+   */
+  public function testSaveChangedUuid() {
+    $config_object = $this->getMockBuilder('Drupal\Core\Config\Config')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $config_object->expects($this->atLeastOnce())
+      ->method('isNew')
+      ->will($this->returnValue(FALSE));
+    $config_object->expects($this->never())
+      ->method('save');
+    $config_object->expects($this->exactly(2))
+      ->method('get')
+      ->will($this->returnValueMap(array(
+        array('', array('id' => 'foo')),
+        array('id', 'foo'),
+      )));
+
+    $this->configFactory->expects($this->at(1))
+      ->method('loadMultiple')
+      ->with(array('the_config_prefix.foo'))
+      ->will($this->returnValue(array()));
+    $this->configFactory->expects($this->at(2))
+      ->method('loadMultiple')
+      ->with(array('the_config_prefix.foo'))
+      ->will($this->returnValue(array($config_object)));
+    $this->configFactory->expects($this->once())
+      ->method('get')
+      ->with('the_config_prefix.foo')
+      ->will($this->returnValue($config_object));
+    $this->configFactory->expects($this->never())
+      ->method('rename')
+      ->will($this->returnValue($config_object));
+
+    $this->moduleHandler->expects($this->exactly(2))
+      ->method('getImplementations')
+      ->will($this->returnValue(array()));
+
+    $this->entityQuery->expects($this->once())
+      ->method('condition')
+      ->will($this->returnSelf());
+    $this->entityQuery->expects($this->once())
+      ->method('execute')
+      ->will($this->returnValue(array('foo')));
+
+    $entity = $this->getMockEntity(array('id' => 'foo'));
+    $this->entityType->expects($this->atLeastOnce())
+      ->method('getClass')
+      ->will($this->returnValue(get_class($entity)));
+
+    $entity->set('uuid', 'baz');
+    $this->entityStorage->save($entity);
+  }
+
+  /**
+   * @covers ::load()
+   * @covers ::postLoad()
+   * @covers ::buildQuery()
+   */
+  public function testLoad() {
+    $config_object = $this->getMockBuilder('Drupal\Core\Config\Config')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $config_object->expects($this->exactly(2))
+      ->method('get')
+      ->will($this->returnValueMap(array(
+        array('', array('id' => 'foo')),
+        array('id', 'foo'),
+      )));
+
+    $this->configFactory->expects($this->once())
+      ->method('loadMultiple')
+      ->with(array('the_config_prefix.foo'))
+      ->will($this->returnValue(array($config_object)));
+    $this->moduleHandler->expects($this->exactly(2))
+      ->method('getImplementations')
+      ->will($this->returnValue(array()));
+
+    $this->entityType->expects($this->atLeastOnce())
+      ->method('getClass')
+      ->will($this->returnValue(get_class($this->getMockEntity())));
+
+    $entity = $this->entityStorage->load('foo');
+    $this->assertInstanceOf('Drupal\Core\Entity\EntityInterface', $entity);
+    $this->assertSame('foo', $entity->id());
+  }
+
+  /**
+   * @covers ::loadMultiple()
+   * @covers ::postLoad()
+   * @covers ::buildQuery()
+   */
+  public function testLoadMultipleAll() {
+    $foo_config_object = $this->getMockBuilder('Drupal\Core\Config\Config')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $foo_config_object->expects($this->exactly(2))
+      ->method('get')
+      ->will($this->returnValueMap(array(
+        array('', array('id' => 'foo')),
+        array('id', 'foo'),
+      )));
+    $bar_config_object = $this->getMockBuilder('Drupal\Core\Config\Config')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $bar_config_object->expects($this->exactly(2))
+      ->method('get')
+      ->will($this->returnValueMap(array(
+        array('', array('id' => 'bar')),
+        array('id', 'bar'),
+      )));
+
+    $this->configFactory->expects($this->once())
+      ->method('loadMultiple')
+      ->with(array())
+      ->will($this->returnValue(array($foo_config_object, $bar_config_object)));
+    $this->moduleHandler->expects($this->exactly(2))
+      ->method('getImplementations')
+      ->will($this->returnValue(array()));
+
+    $this->entityType->expects($this->atLeastOnce())
+      ->method('getClass')
+      ->will($this->returnValue(get_class($this->getMockEntity())));
+
+    $entities = $this->entityStorage->loadMultiple();
+    $expected['foo'] = 'foo';
+    $expected['bar'] = 'bar';
+    foreach ($entities as $id => $entity) {
+      $this->assertInstanceOf('Drupal\Core\Entity\EntityInterface', $entity);
+      $this->assertSame($id, $entity->id());
+      $this->assertSame($expected[$id], $entity->id());
+    }
+  }
+
+  /**
+   * @covers ::loadMultiple()
+   * @covers ::postLoad()
+   * @covers ::buildQuery()
+   */
+  public function testLoadMultipleIds() {
+    $config_object = $this->getMockBuilder('Drupal\Core\Config\Config')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $config_object->expects($this->exactly(2))
+      ->method('get')
+      ->will($this->returnValueMap(array(
+        array('', array('id' => 'foo')),
+        array('id', 'foo'),
+      )));
+
+    $this->configFactory->expects($this->once())
+      ->method('loadMultiple')
+      ->with(array('the_config_prefix.foo'))
+      ->will($this->returnValue(array($config_object)));
+    $this->moduleHandler->expects($this->exactly(2))
+      ->method('getImplementations')
+      ->will($this->returnValue(array()));
+    $this->entityType->expects($this->atLeastOnce())
+      ->method('getClass')
+      ->will($this->returnValue(get_class($this->getMockEntity())));
+
+    $entities = $this->entityStorage->loadMultiple(array('foo'));
+    foreach ($entities as $id => $entity) {
+      $this->assertInstanceOf('Drupal\Core\Entity\EntityInterface', $entity);
+      $this->assertSame($id, $entity->id());
+    }
+  }
+
+  /**
+   * @covers ::loadRevision()
+   */
+  public function testLoadRevision() {
+    $this->assertSame(FALSE, $this->entityStorage->loadRevision(1));
+  }
+
+  /**
+   * @covers ::deleteRevision()
+   */
+  public function testDeleteRevision() {
+    $this->assertSame(NULL, $this->entityStorage->deleteRevision(1));
+  }
+
+  /**
+   * @covers ::delete()
+   */
+  public function testDelete() {
+    $this->entityType->expects($this->atLeastOnce())
+      ->method('getClass')
+      ->will($this->returnValue(get_class($this->getMockEntity())));
+
+    $entities = array();
+    $configs = array();
+    $config_map = array();
+    foreach (array('foo', 'bar') as $id) {
+      $entity = $this->getMockEntity(array('id' => $id));
+      $entities[] = $entity;
+      $config_object = $this->getMockBuilder('Drupal\Core\Config\Config')
+        ->disableOriginalConstructor()
+        ->getMock();
+      $config_object->expects($this->once())
+        ->method('delete');
+      $configs[] = $config_object;
+      $config_map[] = array("the_config_prefix.$id", $config_object);
+    }
+
+    $this->configFactory->expects($this->exactly(2))
+      ->method('get')
+      ->will($this->returnValueMap($config_map));
+
+    $this->moduleHandler->expects($this->at(0))
+      ->method('invokeAll')
+      ->with('test_entity_type_predelete');
+    $this->moduleHandler->expects($this->at(1))
+      ->method('invokeAll')
+      ->with('entity_predelete');
+    $this->moduleHandler->expects($this->at(2))
+      ->method('invokeAll')
+      ->with('test_entity_type_predelete');
+    $this->moduleHandler->expects($this->at(3))
+      ->method('invokeAll')
+      ->with('entity_predelete');
+    $this->moduleHandler->expects($this->at(4))
+      ->method('invokeAll')
+      ->with('test_entity_type_delete');
+    $this->moduleHandler->expects($this->at(5))
+      ->method('invokeAll')
+      ->with('entity_delete');
+    $this->moduleHandler->expects($this->at(6))
+      ->method('invokeAll')
+      ->with('test_entity_type_delete');
+    $this->moduleHandler->expects($this->at(7))
+      ->method('invokeAll')
+      ->with('entity_delete');
+
+    $this->entityStorage->delete($entities);
+  }
+
+  /**
+   * @covers ::delete()
+   */
+  public function testDeleteNothing() {
+    $this->moduleHandler->expects($this->never())
+      ->method($this->anything());
+    $this->configFactory->expects($this->never())
+      ->method('get');
+
+    $this->entityStorage->delete(array());
+  }
+
+  /**
+   * Creates an entity with specific methods mocked.
+   *
+   * @param array $values
+   *   (optional) Values to pass to the constructor.
+   * @param array $methods
+   *   (optional) The methods to mock.
+   *
+   * @return \Drupal\Core\Entity\EntityInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  public function getMockEntity(array $values = array(), $methods = array()) {
+    $methods[] = 'onSaveOrDelete';
+    $methods[] = 'onUpdateBundleEntity';
+    return $this->getMockForAbstractClass('Drupal\Core\Config\Entity\ConfigEntityBase', array($values, 'test_entity_type'), '', TRUE, TRUE, TRUE, $methods);
+  }
+
+}
+
+}
+namespace {
+  if (!defined('SAVED_NEW')) {
+    define('SAVED_NEW', 1);
+  }
+  if (!defined('SAVED_UPDATED')) {
+    define('SAVED_UPDATED', 2);
+  }
+}
