diff --git a/core/lib/Drupal/Core/CoreBundle.php b/core/lib/Drupal/Core/CoreBundle.php
index 4dca804..afad0a3 100644
--- a/core/lib/Drupal/Core/CoreBundle.php
+++ b/core/lib/Drupal/Core/CoreBundle.php
@@ -53,6 +53,10 @@ class CoreBundle extends Bundle
       ->setFactoryMethod('getConnection')
       ->addArgument('slave');
     $container->register('typed_data', 'Drupal\Core\TypedData\TypedDataManager');
+    $container->register('lock', 'Drupal\Core\Lock\DatabaseLockBackend');
+    $container->register('user.tempstore', 'Drupal\user\KeyValueStoreWithOwnerFactory')
+      ->addArgument(new Reference('database'))
+      ->addArgument(new Reference('lock'));
 
     // @todo Replace below lines with the commented out block below it when it's
     //   performant to do so: http://drupal.org/node/1706064.
diff --git a/core/lib/Drupal/Core/KeyValueStore/DatabaseStorage.php b/core/lib/Drupal/Core/KeyValueStore/DatabaseStorage.php
index 4484e9f..e00d6c0 100644
--- a/core/lib/Drupal/Core/KeyValueStore/DatabaseStorage.php
+++ b/core/lib/Drupal/Core/KeyValueStore/DatabaseStorage.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\Core\KeyValueStore;
 
+use Drupal\Core\Database\Query\Merge;
+
 /**
  * Defines a default key/value store implementation.
  *
@@ -16,6 +18,13 @@ namespace Drupal\Core\KeyValueStore;
 class DatabaseStorage extends StorageBase {
 
   /**
+   * The name of the SQL table to use.
+   *
+   * @var string
+   */
+  protected $table;
+
+  /**
    * Overrides Drupal\Core\KeyValueStore\StorageBase::__construct().
    *
    * @param string $collection
@@ -44,9 +53,9 @@ class DatabaseStorage extends StorageBase {
       }
     }
     catch (\Exception $e) {
-      // @todo: Perhaps if the database is never going to be available,
-      // key/value requests should return FALSE in order to allow exception
-      // handling to occur but for now, keep it an array, always.
+      // @todo Perhaps if the database is never going to be available,
+      //   key/value requests should return FALSE in order to allow exception
+      //   handling to occur but for now, keep it an array, always.
     }
     return $values;
   }
@@ -80,6 +89,23 @@ class DatabaseStorage extends StorageBase {
   }
 
   /**
+   * Implements Drupal\Core\KeyValueStore\KeyValueStoreInterface::setIfNotExists().
+   */
+  public function setIfNotExists($key, $value) {
+    $result = db_merge($this->table)
+      ->insertFields(array(
+        'collection' => $this->collection,
+        'name' => $key,
+        'value' => $value,
+      ))
+      ->condition('collection', $this->collection)
+      ->condition('name', $key)
+      ->condition('value', $value)
+      ->execute();
+    return $result == Merge::STATUS_INSERT;
+  }
+
+  /**
    * Implements Drupal\Core\KeyValueStore\KeyValueStoreInterface::deleteMultiple().
    */
   public function deleteMultiple(array $keys) {
diff --git a/core/lib/Drupal/Core/KeyValueStore/DatabaseStorageExpirable.php b/core/lib/Drupal/Core/KeyValueStore/DatabaseStorageExpirable.php
new file mode 100644
index 0000000..47fc243
--- /dev/null
+++ b/core/lib/Drupal/Core/KeyValueStore/DatabaseStorageExpirable.php
@@ -0,0 +1,145 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\Core\KeyValueStore\DatabaseStorageExpirable.
+ */
+
+namespace Drupal\Core\KeyValueStore;
+
+use Drupal\Core\Database\Query\Merge;
+
+/**
+ * Defines a default key/value store implementation for expiring items.
+ *
+ * This is Drupal's default key/value store implementation. It uses the database
+ * to store key/value data with an expire date.
+ */
+class DatabaseStorageExpirable extends DatabaseStorage implements KeyValueStoreExpirableInterface {
+
+  /**
+   * The connection object for this storage.
+   *
+   * @var Drupal\Core\Database\Connection
+   */
+  protected $connection;
+
+  /**
+   * Overrides Drupal\Core\KeyValueStore\StorageBase::__construct().
+   *
+   * @param string $collection
+   *   The name of the collection holding key and value pairs.
+   * @param array $options
+   *   An associative array of options for the key/value storage collection.
+   *   Keys used:
+   *   - table. The name of the SQL table to use, defaults to key_value_expire.
+   */
+  public function __construct($collection, array $options = array()) {
+    parent::__construct($collection, $options);
+    $this->connection = $options['connection'];
+    $this->table = isset($options['table']) ? $options['table'] : 'key_value_expire';
+  }
+
+  /**
+   * Implements Drupal\Core\KeyValueStore\KeyValueStoreInterface::getMultiple().
+   */
+  public function getMultiple(array $keys) {
+    $values = array();
+    try {
+      $result = $this->connection->query('SELECT name, value, expire FROM {' . db_escape_table($this->table) . '} WHERE expire > :now AND name IN (:keys) AND collection = :collection',
+        array(
+          ':now' => REQUEST_TIME,
+          ':keys' => $keys,
+          ':collection' => $this->collection,
+      ))->fetchAllAssoc('name');
+      foreach ($keys as $key) {
+        if (isset($result[$key])) {
+          $values[$key] = unserialize($result[$key]->value);
+        }
+      }
+    }
+    catch (\Exception $e) {
+      // @todo Perhaps if the database is never going to be available,
+      //   key/value requests should return FALSE in order to allow exception
+      //   handling to occur but for now, keep it an array, always.
+    }
+    return $values;
+  }
+
+  /**
+   * Implements Drupal\Core\KeyValueStore\KeyValueStoreInterface::getAll().
+   */
+  public function getAll() {
+    $result = $this->connection->query('SELECT name, value FROM {' . db_escape_table($this->table) . '} WHERE collection = :collection AND expire > :now', array(':collection' => $this->collection, ':now' => REQUEST_TIME));
+    $values = array();
+
+    foreach ($result as $item) {
+      if ($item) {
+        $values[$item->name] = unserialize($item->value);
+      }
+    }
+    return $values;
+  }
+
+  /**
+   * Implements Drupal\Core\KeyValueStore\KeyValueStoreExpireInterface::setWithExpire().
+   */
+  function setWithExpire($key, $value, $expire) {
+    $this->garbageCollection();
+    $this->connection->merge($this->table)
+      ->key(array(
+        'name' => $key,
+        'collection' => $this->collection,
+      ))
+      ->fields(array(
+        'value' => serialize($value),
+        'expire' => REQUEST_TIME + $expire,
+      ))
+      ->execute();
+  }
+
+  /**
+   * Implements Drupal\Core\KeyValueStore\KeyValueStoreInterface::setWithExpireIfNotExists().
+   */
+  function setWithExpireIfNotExists($key, $value, $expire) {
+    $this->garbageCollection();
+    $result = $this->connection->merge($this->table)
+      ->insertFields(array(
+        'collection' => $this->collection,
+        'name' => $key,
+        'value' => serialize($value),
+        'expire' => REQUEST_TIME + $expire,
+      ))
+      ->condition('collection', $this->collection)
+      ->condition('name', $key)
+      ->execute();
+    return $result == MERGE::STATUS_INSERT;
+  }
+
+  /**
+   * Implements Drupal\Core\KeyValueStore\KeyValueStoreInterface::setMultipleWithExpire().
+   */
+  function setMultipleWithExpire(array $data, $expire) {
+    foreach ($data as $key => $value) {
+      $this->set($key, $value, $expire);
+    }
+  }
+
+  /**
+   * Implements Drupal\Core\KeyValueStore\KeyValueStoreInterface::deleteMultiple().
+   */
+  public function deleteMultiple(array $keys) {
+    $this->garbageCollection();
+    parent::deleteMultiple($keys);
+  }
+
+  /**
+   * Deletes expired items.
+   */
+  protected function garbageCollection() {
+    $this->connection->delete($this->table)
+      ->condition('expire', REQUEST_TIME, '<')
+      ->execute();
+  }
+
+}
diff --git a/core/lib/Drupal/Core/KeyValueStore/KeyValueStoreExpirableInterface.php b/core/lib/Drupal/Core/KeyValueStore/KeyValueStoreExpirableInterface.php
new file mode 100644
index 0000000..113c6c6
--- /dev/null
+++ b/core/lib/Drupal/Core/KeyValueStore/KeyValueStoreExpirableInterface.php
@@ -0,0 +1,52 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface.
+ */
+
+namespace Drupal\Core\KeyValueStore;
+
+/**
+ * Defines the interface for expiring date in a key/value store.
+ */
+interface KeyValueStoreExpirableInterface extends KeyValueStoreInterface {
+
+  /**
+   * Saves a value for a given key with a time to live.
+   *
+   * @param string $key
+   *   The key of the data to store.
+   * @param mixed $value
+   *   The data to store.
+   * @param int $expire
+   *   The time to live for items, in seconds.
+   */
+  function setWithExpire($key, $value, $expire);
+
+  /**
+   * Sets a value for a given key with a time to live, if it does not exist yet.
+   *
+   * @param string $key
+   *   The key of the data to store.
+   * @param mixed $value
+   *   The data to store.
+   * @param int $expire
+   *   The time to live for items, in seconds.
+   *
+   * @return bool
+   *   TRUE if the data was set, FALSE if it already existed.
+   */
+  function setWithExpireIfNotExists($key, $value, $expire);
+
+  /**
+   * Saves an array of values with a time to live.
+   *
+   * @param array $data
+   *   An array of data to store.
+   * @param int $expire
+   *   The time to live for items, in seconds.
+   */
+  function setMultipleWithExpire(array $data, $expire);
+
+}
diff --git a/core/lib/Drupal/Core/KeyValueStore/KeyValueStoreInterface.php b/core/lib/Drupal/Core/KeyValueStore/KeyValueStoreInterface.php
index 9e7bb34..0b653b5 100644
--- a/core/lib/Drupal/Core/KeyValueStore/KeyValueStoreInterface.php
+++ b/core/lib/Drupal/Core/KeyValueStore/KeyValueStoreInterface.php
@@ -73,6 +73,19 @@ interface KeyValueStoreInterface {
   public function set($key, $value);
 
   /**
+   * Saves a value for a given key if it does not exist yet.
+   *
+   * @param string $key
+   *   The key of the data to store.
+   * @param mixed $value
+   *   The data to store.
+   *
+   * @return bool
+   *   TRUE if the data was set, FALSE if it already existed.
+   */
+  public function setIfNotExists($key, $value);
+
+  /**
    * Saves key/value pairs.
    *
    * @param array $data
diff --git a/core/lib/Drupal/Core/KeyValueStore/MemoryStorage.php b/core/lib/Drupal/Core/KeyValueStore/MemoryStorage.php
index 4724005..a025dbc 100644
--- a/core/lib/Drupal/Core/KeyValueStore/MemoryStorage.php
+++ b/core/lib/Drupal/Core/KeyValueStore/MemoryStorage.php
@@ -65,6 +65,17 @@ class MemoryStorage implements KeyValueStoreInterface {
   }
 
   /**
+   * Implements Drupal\Core\KeyValueStore\KeyValueStoreInterface::setIfNotExists().
+   */
+  public function setIfNotExists($key, $value) {
+    if (!isset($this->data[$key])) {
+      $this->data[$key] = $value;
+      return TRUE;
+    }
+    return FALSE;
+  }
+
+  /**
    * Implements Drupal\Core\KeyValueStore\KeyValueStoreInterface::setMultiple().
    */
   public function setMultiple(array $data) {
diff --git a/core/modules/system/system.install b/core/modules/system/system.install
index 3790f2b..88eb9c8 100644
--- a/core/modules/system/system.install
+++ b/core/modules/system/system.install
@@ -832,6 +832,43 @@ function system_schema() {
     'primary key' => array('collection', 'name'),
   );
 
+  $schema['key_value_expire'] = array(
+    'description' => 'Generic key-value storage table with an expire.',
+    'fields' => array(
+      'collection' => array(
+        'description' => 'A named collection of key and value pairs.',
+        'type' => 'varchar',
+        'length' => 128,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'name' => array(
+        'description' => 'The key of the key-value pair. As KEY is a SQL reserved keyword, name was chosen instead.',
+        'type' => 'varchar',
+        'length' => 128,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'value' => array(
+        'description' => 'The value.',
+        'type' => 'blob',
+        'not null' => TRUE,
+        'size' => 'big',
+        'translatable' => TRUE,
+      ),
+      'expire' => array(
+        'description' => 'The time since Unix epoch in seconds when this item expires.',
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+    ),
+    'primary key' => array('collection', 'name'),
+    'indexes' => array(
+      'all' => array('name', 'collection', 'expire'),
+    ),
+  );
+
   $schema['menu_router'] = array(
     'description' => 'Maps paths to various callbacks (access, page and title)',
     'fields' => array(
@@ -1976,6 +2013,50 @@ function system_update_8021() {
 }
 
 /**
+ * Create the 'key_value_expire' table.
+ */
+function system_update_8022() {
+  $table = array(
+    'description' => 'Generic key-value storage table with an expire.',
+    'fields' => array(
+      'collection' => array(
+        'description' => 'A named collection of key and value pairs.',
+        'type' => 'varchar',
+        'length' => 128,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'name' => array(
+        'description' => 'The key of the key-value pair. As KEY is a SQL reserved keyword, name was chosen instead.',
+        'type' => 'varchar',
+        'length' => 128,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'value' => array(
+        'description' => 'The value.',
+        'type' => 'blob',
+        'not null' => TRUE,
+        'size' => 'big',
+        'translatable' => TRUE,
+      ),
+      'expire' => array(
+        'description' => 'The time since Unix epoch in seconds when this item expires.',
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+    ),
+    'primary key' => array('collection', 'name'),
+    'indexes' => array(
+      'all' => array('name', 'collection', 'expire'),
+    ),
+  );
+
+  db_create_table('key_value_expire', $table);
+}
+
+/**
  * @} End of "defgroup updates-7.x-to-8.x".
  * The next series of updates should start at 9000.
  */
diff --git a/core/modules/user/lib/Drupal/user/KeyValueStoreWithOwner.php b/core/modules/user/lib/Drupal/user/KeyValueStoreWithOwner.php
new file mode 100644
index 0000000..24478c9
--- /dev/null
+++ b/core/modules/user/lib/Drupal/user/KeyValueStoreWithOwner.php
@@ -0,0 +1,155 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\user\KeyValueStoreWithOwner.
+ */
+
+namespace Drupal\user;
+
+use Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface;
+use Drupal\Core\Lock\LockBackendInterface;
+
+/**
+ * Stores and retrieves values from a key/value store with a default key.
+ */
+class KeyValueStoreWithOwner {
+
+  /**
+   * The key/value storage object used for this data.
+   *
+   * @var Drupal\Core\KeyValueStore\KeyValueStoreExpireInterface;
+   */
+  protected $storage;
+
+  /**
+   * The lock object used for this data.
+   *
+   * @var Drupal\Core\Lock\LockBackendInterface
+   */
+  protected $lockBackend;
+
+  /**
+   * The owner key to store along with the data.
+   *
+   * @var mixed
+   */
+  protected $owner;
+
+  /**
+   * The time to live for items in seconds. Defaults to a week.
+   *
+   * @var int
+   */
+  protected $expire = 604800;
+
+  /**
+   * Constructs a new object for accessing data from a key/value store.
+   *
+   * @param KeyValueStoreExpireInterface $storage
+   *   The key/value storage object used for this data.
+   * @param Drupal\Core\Lock\LockBackendInterface $lockBackend
+   *   The lock object used for this data.
+   * @param mixed $owner
+   *   The owner key to store along with the data.
+   */
+  function __construct(KeyValueStoreExpirableInterface $storage, LockBackendInterface $lockBackend, $owner) {
+    $this->storage = $storage;
+    $this->lockBackend = $lockBackend;
+    $this->owner = $owner;
+  }
+
+  /**
+   * Returns the stored value for the default key.
+   *
+   * @param string $key
+   *   The key of the data to retrieve.
+   *
+   * @return mixed
+   *   The data to retieve, or NULL if the key does not exist.
+   */
+  function get($key) {
+    if ($object = $this->storage->get($key)) {
+      return $object->data;
+    }
+  }
+
+  /**
+   * Adds the value for the default key if it doesn't exist yet.
+   *
+   * @param string $key
+   *   The key of the data to check and store.
+   * @param mixed $value
+   *   The data to store.
+   *
+   * @return bool
+   *   TRUE if the data was set, FALSE if it already existed.
+   */
+  function setIfNotExists($key, $value) {
+    $value = (object) array(
+      'owner' => $this->owner,
+      'data' => $value,
+      'updated' => REQUEST_TIME,
+    );
+    return $this->storage->setWithExpireIfNotExists($key, $value, $this->expire);
+  }
+
+  /**
+   * Sets the value for the default key.
+   *
+   * @param string $key
+   *   The key of the data to store.
+   * @param mixed $value
+   *   The data to store.
+   */
+  function set($key, $value) {
+    if ($this->lockBackend->acquire($key)) {
+      $object = $this->storage->get($key);
+      if (!$object || $object->owner == $this->owner) {
+        $value = (object) array(
+          'owner' => $this->owner,
+          'data' => $value,
+          'updated' => REQUEST_TIME,
+        );
+        $this->storage->setWithExpire($key, $value, $this->expire);
+      }
+      $this->lockBackend->release($key);
+    }
+  }
+
+  /**
+   * Gets the metadata for a key.
+   *
+   * @param string $key
+   *   The key of the data to store.
+   *
+   * @return mixed
+   *   An object with the owner and updated time if the key has a value, NULL
+   *   otherwise.
+   */
+  function getMetadata($key) {
+    $object = $this->storage->get($key);
+    if ($object) {
+      unset($object->data);
+      return $object;
+    }
+  }
+
+  /**
+   * Deletes the value of the default key.
+   *
+   * @param string $key
+   *   The key of the data to store.
+   */
+  function delete($key) {
+    if (!$this->lockBackend->acquire($key)) {
+      $this->lockBackend->wait($key);
+      if (!$this->lockBackend->acquire($key)) {
+        throw new KeyValueStoreWithOwnerException("Couldn't acquire lock");
+      }
+    }
+    $this->storage->delete($key);
+    $this->lockBackend->release($key);
+  }
+
+}
diff --git a/core/modules/user/lib/Drupal/user/KeyValueStoreWithOwnerException.php b/core/modules/user/lib/Drupal/user/KeyValueStoreWithOwnerException.php
new file mode 100644
index 0000000..4a35e23
--- /dev/null
+++ b/core/modules/user/lib/Drupal/user/KeyValueStoreWithOwnerException.php
@@ -0,0 +1,13 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\Core\KeyValueStore\KeyValueStoreDefaultException.
+ */
+
+namespace Drupal\user;
+
+/**
+ * Exception thrown when KeyValueStoreWithOwner can not acquire a lock.
+ */
+class KeyValueStoreWithOwnerException extends \Exception {}
diff --git a/core/modules/user/lib/Drupal/user/KeyValueStoreWithOwnerFactory.php b/core/modules/user/lib/Drupal/user/KeyValueStoreWithOwnerFactory.php
new file mode 100644
index 0000000..dc389ba
--- /dev/null
+++ b/core/modules/user/lib/Drupal/user/KeyValueStoreWithOwnerFactory.php
@@ -0,0 +1,60 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\user\KeyValueStoreWithOwnerFactory.
+ */
+
+namespace Drupal\user;
+
+use Drupal\Core\Database\Connection;
+use Drupal\Core\KeyValueStore\DatabaseStorageExpirable;
+use Drupal\Core\Lock\LockBackendInterface;
+
+/**
+ * Provides a factory for key/value storage that needs an owner.
+ */
+class KeyValueStoreWithOwnerFactory {
+
+  /**
+   * The connection object used for this data.
+   *
+   * @var Drupal\Core\Database\Connection $connection
+   */
+  protected $connection;
+
+  /**
+   * The lock object used for this data.
+   *
+   * @var Drupal\Core\Lock\LockBackendInterface $lockBackend
+   */
+  protected $lockBackend;
+
+  /**
+   * Constructs a Drupal\user\KeyValueStoreWithOwnerFactory object.
+   *
+   * @param Drupal\Core\Database\Connection $connection
+   *   The connection object used for this data.
+   * @param Drupal\Core\Lock\LockBackendInterface $lockBackend
+   *   The lock object used for this data.
+   */
+  function __construct(Connection $connection, LockBackendInterface $lockBackend) {
+    $this->connection = $connection;
+    $this->lockBackend = $lockBackend;
+  }
+
+  /**
+   * Creates a Drupal\user\KeyValueStoreWithOwner stored in the database.
+   *
+   * @param string $namespace
+   *   The namespace to use for this key/value store.
+   *
+   * @return Drupal\user\KeyValueStoreWithOwner
+   *   An instance of the the key/value store.
+   */
+  function get($namespace) {
+    $storage = new DatabaseStorageExpirable($namespace, array('connection' => $this->connection));
+    return new KeyValueStoreWithOwner($storage, $this->lockBackend, $GLOBALS['user']->uid ?: session_id());
+  }
+
+}
diff --git a/core/modules/user/lib/Drupal/user/Tests/TempStoreDatabaseTest.php b/core/modules/user/lib/Drupal/user/Tests/TempStoreDatabaseTest.php
new file mode 100644
index 0000000..4927ffa
--- /dev/null
+++ b/core/modules/user/lib/Drupal/user/Tests/TempStoreDatabaseTest.php
@@ -0,0 +1,165 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\user\Tests\TempStoreDatabaseTest.
+ */
+
+namespace Drupal\user\Tests;
+
+use Drupal\simpletest\UnitTestBase;
+use Drupal\user\KeyValueStoreWithOwnerFactory;
+use Drupal\Core\Lock\DatabaseLockBackend;
+use Drupal\Core\Database\Database;
+use stdClass;
+
+/**
+ * Tests the TempStore namespace.
+ *
+ * @see Drupal\Core\TempStore\TempStore.
+ */
+class TempStoreDatabaseTest extends UnitTestBase {
+
+  /**
+   * A key/value store factory.
+   *
+   * @var Drupal\user\KeyValueStoreWithOwnerFactory
+   */
+  protected $storeFactory;
+
+  /**
+   * The name of the collection to set and retrieve.
+   *
+   * @var string
+   */
+  protected $collection;
+
+  /**
+   * An array of (fake) user ids.
+   *
+   * @var array
+   */
+  protected $users = array();
+
+  /**
+   * An array of random stdClass objects.
+   *
+   * @var array
+   */
+  protected $objects = array();
+
+  public static function getInfo() {
+    return array(
+      'name' => 'TempStore',
+      'description' => 'Tests the temporary object storage system.',
+      'group' => 'TempStore',
+    );
+  }
+
+  protected function setUp() {
+    parent::setUp();
+    module_load_install('system');
+    $schema = system_schema();
+    db_create_table('semaphore', $schema['semaphore']);
+    db_create_table('key_value_expire', $schema['key_value_expire']);
+    $this->storeFactory = new KeyValueStoreWithOwnerFactory(Database::getConnection(), new DatabaseLockBackend());
+    $this->collection = $this->randomName();
+
+    // Create two users and two objects for testing.
+    for ($i = 0; $i <= 3; $i++) {
+      $this->objects[$i] = $this->randomObject();
+      $this->users[$i] = mt_rand(500, 5000000);
+    }
+  }
+
+  /**
+   * Generates a random PHP object.
+   *
+   * @param int $size
+   *   The number of random keys to add to the object.
+   *
+   * @return stdClass
+   *   The generated object, with the specified number of random keys. Each key
+   *   has a random string value.
+   */
+  public function randomObject($size = 4) {
+    $object = new stdClass();
+    for ($i = 0; $i < $size; $i++) {
+      $random_key = $this->randomName();
+      $random_value = $this->randomString();
+      $object->{$random_key} = $random_value;
+    }
+    return $object;
+  }
+
+  /**
+   * Tests the UserTempStore API.
+   */
+  public function testUserTempStore() {
+    $key = $this->randomName();
+    // First test that only one setIfNotExists succeeds.
+    for ($i = 0; $i <= 1; $i++) {
+      $store = $this->getStorePerUid($this->users[$i]);
+      // Setting twice results only in the first succeeding.
+      $this->assertEqual(!$i, $store->setIfNotExists($key, $this->objects[$i]));
+      $metadata = $store->getMetadata($key);
+      $this->assertEqual($this->users[0], $metadata->owner);
+      $this->assertIdenticalObject($this->objects[0], $store->get($key));
+    }
+    // Remove the item.
+    $store->delete($key);
+    // Try to set it again.
+    $store->setIfNotExists($key, $this->objects[1]);
+    // This time it succeeds.
+    $this->assertIdenticalObject($this->objects[1], $store->get($key));
+    // This user can update the object.
+    $store->set($key, $this->objects[2]);
+    $this->assertIdenticalObject($this->objects[2], $store->get($key));
+    // But another can't.
+    $store = $this->getStorePerUid($this->users[2]);
+    $store->set($key, $this->objects[3]);
+    $this->assertIdenticalObject($this->objects[2], $store->get($key));
+    // Now manually expire the item (this is not exposed by the API) and then
+    // assert it is no longer accessible.
+    db_update('key_value_expire')
+      ->fields(array('expire' => REQUEST_TIME - 1))
+      ->condition('collection', $this->collection)
+      ->condition('name', $key)
+      ->execute();
+    $this->assertFalse($store->get($key));
+  }
+
+  /**
+   * Returns a KeyValueStoreWithOwner belonging to the passed in user.
+   *
+   * @param int $uid
+   *   A user ID.
+   *
+   * @return Drupal\user\KeyValueStoreWithOwner
+   *   The key/value store object.
+   */
+  protected function getStorePerUid($uid) {
+    $GLOBALS['user']->uid = $uid;
+    // This relies on the logged user uid!!
+    return $this->storeFactory->get($this->collection);
+  }
+
+  /**
+   * Checks to see if two objects are identical.
+   *
+   * @param object $object1
+   *   The first object to check.
+   * @param object $object2
+   *   The second object to check.
+   */
+  protected function assertIdenticalObject($object1, $object2) {
+    $identical = TRUE;
+    foreach ($object1 as $key => $value) {
+      $identical = $identical && isset($object2->$key) && $object2->$key === $value;
+    }
+    $this->assertTrue($identical, format_string('!object1 is identical to !object2', array(
+      '!object1' => var_export($object1, TRUE),
+      '!object2' => var_export($object2, TRUE),
+    )));
+  }
+}
