diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc
index aa158a2..a1846d1 100644
--- a/core/includes/install.core.inc
+++ b/core/includes/install.core.inc
@@ -1907,16 +1907,15 @@ function _install_prepare_import($langcode) {
     // we check if at least the major version number is available.
     if ($info['major']) {
       $core = $info['major'] . '.x';
-      db_insert('locale_project')
-        ->fields(array(
-          'name' => 'drupal',
-          'project_type' => 'module',
-          'core' => $core,
-          'version' => $version,
-          'server_pattern' => $install_state['server_pattern'],
-          'status' => 1,
-        ))
-        ->execute();
+      $data = array(
+        'name' => 'drupal',
+        'project_type' => 'module',
+        'core' => $core,
+        'version' => $version,
+        'server_pattern' => $install_state['server_pattern'],
+        'status' => 1,
+      );
+      \Drupal::service('locale.project')->set($data['name'], $data);
       module_load_include('compare.inc', 'locale');
       locale_translation_check_projects_local(array('drupal'), array($install_state['parameters']['langcode']));
     }
diff --git a/core/modules/locale/lib/Drupal/locale/LocalProjectStorageInterface.php b/core/modules/locale/lib/Drupal/locale/LocalProjectStorageInterface.php
new file mode 100644
index 0000000..81748ed
--- /dev/null
+++ b/core/modules/locale/lib/Drupal/locale/LocalProjectStorageInterface.php
@@ -0,0 +1,106 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\locale\LocalProjectStorageInterface.
+ */
+
+namespace Drupal\locale;
+
+/**
+ * Defines the locale project storage interface.
+ */
+interface LocaleProjectStorageInterface {
+
+  /**
+   * Returns the stored value for a given key.
+   *
+   * @param string $key
+   *   The key of the data to retrieve.
+   * @param mixed $default
+   *   The default value to use if the key is not found.
+   *
+   * @return mixed
+   *   The stored value, or the default value if no value exists.
+   */
+  public function get($key, $default = NULL);
+
+  /**
+   * Returns a list project records.
+   *
+   * @param array $keys
+   *   A list of keys to retrieve.
+   *
+   * @return array
+   *   An associative array of items successfully returned, indexed by key.
+   */
+  public function getMultiple(array $keys);
+
+  /**
+   * Creates or updates the project record.
+   *
+   * @param string $key
+   *   The key of the data to store.
+   * @param mixed $value
+   *   The data to store.
+   */
+  public function set($key, $value);
+
+  /**
+   * Creates or updates multiple project records.
+   *
+   * @param array $data
+   *   An associative array of key/value pairs.
+   */
+  public function setMultiple(array $data);
+
+  /**
+   * Deletes project records for a given key.
+   *
+   * @param string $key
+   *   The key of the data to delete.
+   */
+  public function delete($key);
+
+  /**
+   * Deletes multiple project records.
+   *
+   * @param array $keys
+   *   A list of item names to delete.
+   */
+  public function deleteMultiple(array $keys);
+
+  /**
+   * Returns all the project records.
+   *
+   * @return array
+   *   An associative array of items successfully returned, indexed by key.
+   */
+  public function getAll();
+
+  /**
+   * Deletes all projects records.
+   *
+   * @return array
+   *   An associative array of items successfully returned, indexed by key.
+   */
+  public function deleteAll();
+
+  /**
+   * Mark all projects as disabled.
+   */
+  public function disableAll();
+
+  /**
+   * Resets the project storage cache.
+   */
+  public function resetCache();
+
+  /**
+   * Returns the count of project records.
+   *
+   * @return int
+   *   The number of saved items.
+   */
+  public function countProjects();
+}
diff --git a/core/modules/locale/lib/Drupal/locale/LocaleProjectStorage.php b/core/modules/locale/lib/Drupal/locale/LocaleProjectStorage.php
new file mode 100644
index 0000000..f4a6c7f
--- /dev/null
+++ b/core/modules/locale/lib/Drupal/locale/LocaleProjectStorage.php
@@ -0,0 +1,173 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\locale\LocaleProjectStorage.
+ */
+
+namespace Drupal\locale;
+
+use Drupal\Core\KeyValueStore\KeyValueFactoryInterface;
+
+/**
+ * Provides the locale project storage system using a key value store.
+ */
+class LocaleProjectStorage implements LocaleProjectStorageInterface {
+
+  /**
+   * The key value store to use.
+   *
+   * @var \Drupal\Core\KeyValueStore\KeyValueStoreInterface
+   */
+  protected $keyValueStore;
+
+  /**
+   * Static state cache.
+   *
+   * @var array
+   */
+  protected $cache = array();
+
+  /**
+   * Cache status flag.
+   *
+   * @var bool
+   */
+  protected static $all = FALSE;
+
+  /**
+   * Constructs a State object.
+   *
+   * @param \Drupal\Core\KeyValueStore\KeyValueFactoryInterface $key_value_factory
+   *   The key value store to use.
+   */
+  function __construct(KeyValueFactoryInterface $key_value_factory) {
+    $this->keyValueStore = $key_value_factory->get('locale.project');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function get($key, $default = NULL) {
+    $values = $this->getMultiple(array($key));
+    return isset($values[$key]) ? $values[$key] : $default;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getMultiple(array $keys) {
+    $values = array();
+    $load = array();
+    foreach ($keys as $key) {
+      // Check if we have a value in the cache.
+      if (isset($this->cache[$key])) {
+        $values[$key] = $this->cache[$key];
+      }
+      // Load the value if we don't have an explicit NULL value.
+      elseif (!array_key_exists($key, $this->cache)) {
+        $load[] = $key;
+      }
+    }
+
+    if ($load) {
+      $loaded_values = $this->keyValueStore->getMultiple($load);
+      foreach ($load as $key) {
+        // If we find a value, even one that is NULL, add it to the cache and
+        // return it.
+        if (isset($loaded_values[$key])) {
+          $values[$key] = $loaded_values[$key];
+          $this->cache[$key] = $loaded_values[$key];
+        }
+        else {
+          $this->cache[$key] = NULL;
+        }
+      }
+    }
+
+    return $values;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function set($key, $value) {
+    $this->setMultiple(array($key => $value));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setMultiple(array $data) {
+    foreach ($data as $key => $value) {
+      $this->cache[$key] = $value;
+    }
+    $this->keyValueStore->setMultiple($data);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function delete($key) {
+    $this->deleteMultiple(array($key));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function deleteMultiple(array $keys) {
+    foreach ($keys as $key) {
+      $this->cache[$key] = NULL;
+    }
+    $this->keyValueStore->deleteMultiple($keys);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function resetCache() {
+    $this->cache = array();
+    static::$all = FALSE;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function deleteAll() {
+    $this->keyValueStore->deleteAll();
+    $this->resetCache();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function disableAll() {
+    $projects = $this->keyValueStore->getAll();
+    foreach ($projects as $key) {
+      $projects[$key]['status'] = 0;
+      if (isset($cache[$key])) {
+        $cache[$key] = $projects[$key];
+      }
+    }
+    $this->keyValueStore->setMultiple($projects);
+
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function countProjects() {
+    return count($this->getAll());
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getAll() {
+    if (!static::$all) {
+      $this->cache = $this->keyValueStore->getAll();
+      static::$all = TRUE;
+    }
+    return $this->cache;
+  }
+}
diff --git a/core/modules/locale/locale.compare.inc b/core/modules/locale/locale.compare.inc
index dad67a8..0a7f35e 100644
--- a/core/modules/locale/locale.compare.inc
+++ b/core/modules/locale/locale.compare.inc
@@ -19,9 +19,7 @@
  * Clear the project data table.
  */
 function locale_translation_flush_projects() {
-  // Followup issue: http://drupal.org/node/1842362
-  // Replace {locale_project} table by \Drupal::state() variable(s).
-  db_truncate('locale_project')->execute();
+  Drupal::service('locale.project')->deleteAll();
 }

 /**
@@ -55,11 +53,7 @@ function locale_translation_build_projects() {
   $projects = locale_translation_project_list();

   // Mark all previous projects as disabled and store new project data.
-  db_update('locale_project')
-    ->fields(array(
-      'status' => 0,
-    ))
-    ->execute();
+  \Drupal::service('locale.project')->disableAll();

   $default_server = locale_translation_default_translation_server();

@@ -91,6 +85,7 @@ function locale_translation_build_projects() {

     // For every project store information.
     $data += array(
+      'name' => $name,
       'version' => isset($data['info']['version']) ? $data['info']['version'] : '',
       'core' => isset($data['info']['core']) ? $data['info']['core'] : \Drupal::CORE_COMPATIBILITY,
       // A project can provide the path and filename pattern to download the
@@ -102,20 +97,10 @@ function locale_translation_build_projects() {
     $projects[$name] = $project;

     // Create or update the project record.
-    db_merge('locale_project')
-      ->key('name', $project->name)
-      ->fields(array(
-        'name' => $project->name,
-        'project_type' => $project->project_type,
-        'core' => $project->core,
-        'version' => $project->version,
-        'server_pattern' => $project->server_pattern,
-        'status' => $project->status,
-      ))
-      ->execute();
+    \Drupal::service('locale.project')->set($project->name, $data);

-      // Invalidate the cache of translatable projects.
-      locale_translation_clear_cache_projects();
+    // Invalidate the cache of translatable projects.
+    locale_translation_clear_cache_projects();
   }
   return $projects;
 }
diff --git a/core/modules/locale/locale.install b/core/modules/locale/locale.install
index c62c842..3392959 100644
--- a/core/modules/locale/locale.install
+++ b/core/modules/locale/locale.install
@@ -228,55 +228,6 @@ function locale_schema() {
     ),
     'primary key' => array('project', 'langcode'),
   );
-
-  $schema['locale_project'] = array(
-    'description' => 'Translation status information for projects and server data.',
-    'fields' => array(
-      'name' => array(
-        'description' => 'A unique short name to identify the project.',
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-      ),
-      'project_type' => array(
-        'description' => 'Project type: core, module, or theme.',
-        'type' => 'varchar',
-        'length' => 15,
-        'not null' => TRUE,
-      ),
-      'core' => array(
-        // http://drupal.org/node/542202#core has an example.
-        'description' => 'Core compatibility string for this project, for example: 8.x',
-        'type' => 'varchar',
-        'length' => 4,
-        'not null' => TRUE,
-        'default' => '',
-      ),
-      'version' => array(
-        // http://drupal.org/node/467026 has examples.
-        'description' => 'The version release of the project, for example: 8.x-2.1 or 8.x-1.0-dev',
-        'type' => 'varchar',
-        'length' => 128,
-        'not null' => TRUE,
-        'default' => '',
-      ),
-      'server_pattern' => array(
-        'description' => 'Pattern of path and name of the gettext file at the translation server.',
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => '',
-      ),
-      'status' => array(
-        // locale.compare.inc gives possible values for status.
-        'description' => 'The status of the project. Possible values are: 1 = enabled, 0 = disabled.',
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 1,
-      ),
-    ),
-    'primary key' => array('name'),
-  );
   return $schema;
 }

diff --git a/core/modules/locale/locale.module b/core/modules/locale/locale.module
index 881ca9a..4584044 100644
--- a/core/modules/locale/locale.module
+++ b/core/modules/locale/locale.module
@@ -522,9 +522,7 @@ function locale_system_remove($components) {
       // Remove translatable projects.
       // Followup issue http://drupal.org/node/1842362 to replace the
       // {locale_project} table. Then change this to a function call.
-      db_delete('locale_project')
-        ->condition('name', $list)
-        ->execute();
+      \Drupal::service('locale.project')->deleteMultiple($list);

       // Clear the translation status.
       locale_translation_status_delete_projects($list);
diff --git a/core/modules/locale/locale.services.yml b/core/modules/locale/locale.services.yml
index 559a066..d1c0aef 100644
--- a/core/modules/locale/locale.services.yml
+++ b/core/modules/locale/locale.services.yml
@@ -10,6 +10,9 @@ services:
   locale.storage:
     class: Drupal\locale\StringDatabaseStorage
     arguments: ['@database']
+  locale.project:
+    class: Drupal\locale\LocaleProjectStorage
+    arguments: ['@keyvalue']
   string_translator.locale.lookup:
     class: Drupal\locale\LocaleTranslation
     arguments: ['@locale.storage', '@cache.default', '@lock', '@config.factory', '@language_manager']
diff --git a/core/modules/locale/locale.translation.inc b/core/modules/locale/locale.translation.inc
index fab2a21..5704f80 100644
--- a/core/modules/locale/locale.translation.inc
+++ b/core/modules/locale/locale.translation.inc
@@ -54,8 +54,7 @@ function locale_translation_get_projects($project_names = array()) {

   if (empty($projects)) {
     // Get project data from the database.
-    $row_count = db_query_range('SELECT 1 FROM {locale_project}', 0, 1)->fetchField();
-
+    $row_count = \Drupal::service('locale.project')->countProjects();
     // http://drupal.org/node/1777106 is a follow-up issue to make the check for
     // possible out-of-date project information more robust.
     if ($row_count == 0 && \Drupal::moduleHandler()->moduleExists('update')) {
@@ -64,11 +63,10 @@ function locale_translation_get_projects($project_names = array()) {
       // data if none are found.
       locale_translation_build_projects();
     }
-    $result = db_query('SELECT name, project_type, core, version, server_pattern, status FROM {locale_project}');
-
-    foreach ($result as $project) {
-      $projects[$project->name] = $project;
-    }
+    $projects = \Drupal::service('locale.project')->getAll();
+    array_walk($projects, function(&$project) {
+      $project = (object) $project;
+    });
   }

   // Return the requested project names or all projects.
@@ -326,13 +324,17 @@ function locale_cron_fill_queue() {

   // Determine which project+language should be updated.
   $last = REQUEST_TIME - $config->get('translation.update_interval_days') * 3600 * 24;
-  $query = db_select('locale_file', 'f');
-  $query->join('locale_project', 'p', 'p.name = f.project');
-  $query->condition('f.last_checked', $last, '<');
-  $query->fields('f', array('project', 'langcode'));
-  // Only currently installed / enabled components should be checked for.
-  $query->condition('p.status', 1);
-  $files = $query->execute()->fetchAll();
+  $projects = \Drupal::service('locale.project')->getAll();
+  $projects = array_filter($projects, function($project) {
+    return $project['status'] == 1;
+  });
+  $files = db_select('locale_file', 'f')
+    ->condition('f.project', array_keys($projects))
+    ->condition('f.last_checked', $last, '<')
+    ->fields('f', array('project', 'langcode'))
+    // Only currently installed / enabled components should be checked for.
+    ->condition('p.status', 1)
+    ->execute()->fetchAll();
   foreach ($files as $file) {
     $updates[$file->project][] = $file->langcode;

