diff --git a/core/core.services.yml b/core/core.services.yml
index 882cf9f..e10a471 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -141,6 +141,9 @@ services:
     factory_method: get
     factory_service: keyvalue
     arguments: [state]
+  schema:
+    class: Drupal\Core\Schema\Schema
+    arguments: ['@module_handler', '@cache.cache', '@keyvalue']
   queue:
     class: Drupal\Core\Queue\QueueFactory
     arguments: ['@settings']
diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc
index 9159f71..14b3d6e 100644
--- a/core/includes/install.core.inc
+++ b/core/includes/install.core.inc
@@ -313,7 +313,6 @@ function install_begin_request(&$install_state) {
   require_once __DIR__ . '/common.inc';
   require_once __DIR__ . '/file.inc';
   require_once __DIR__ . '/install.inc';
-  require_once __DIR__ . '/schema.inc';
   require_once __DIR__ . '/../../' . settings()->get('path_inc', 'core/includes/path.inc');
 
   // Load module basics (needed for hook invokes).
@@ -414,6 +413,11 @@ function install_begin_request(&$install_state) {
     $container
       ->register('module_handler', 'Drupal\Core\Extension\ModuleHandler');
 
+    $container->register('schema', 'Drupal\Core\Schema\Schema')
+      ->addArgument(new Reference('module_handler'))
+      ->addArgument(new Reference('cache.cache'))
+      ->addArgument(new Reference('keyvalue'));
+
     // Register the Guzzle HTTP client for fetching translation files from a
     // remote translation server such as localization.drupal.org.
     $container->register('http_default_client', 'Guzzle\Http\Client')
@@ -2114,7 +2118,7 @@ function install_configure_form($form, &$form_state, &$install_state) {
   // try to generate one but with no loaded modules will return nothing.
   //
   // @todo Move this to the 'install_finished' task?
-  drupal_get_schema(NULL, TRUE);
+  \Drupal::service('schema')->getSchema(NULL, TRUE);
 
   // Return the form.
   return _install_configure_form($form, $form_state, $install_state);
diff --git a/core/includes/install.inc b/core/includes/install.inc
index 4e70be4..733cb98 100644
--- a/core/includes/install.inc
+++ b/core/includes/install.inc
@@ -622,18 +622,18 @@ function drupal_verify_profile($install_state) {
  * functions can be made available while other modules are installed.
  */
 function drupal_install_system() {
-  // Create tables.
-  drupal_install_schema('system');
-
   if (!drupal_container()->has('kernel')) {
     // Immediately boot a kernel to have real services ready.
     $kernel = new DrupalKernel('install', drupal_classloader(), FALSE);
     $kernel->boot();
   }
 
+  // Create tables.
+  \Drupal::service('schema')->installSchema('system');
+
   $system_path = drupal_get_path('module', 'system');
   require_once DRUPAL_ROOT . '/' . $system_path . '/system.install';
-  $system_versions = drupal_get_schema_versions('system');
+  $system_versions = \Drupal::service('schema')->getSchemaVersions('system');
   $system_version = $system_versions ? max($system_versions) : SCHEMA_INSTALLED;
   \Drupal::keyValue('system.schema')->set('system', $system_version);
 
diff --git a/core/includes/schema.inc b/core/includes/schema.inc
index 45b4b23..8c0cadc 100644
--- a/core/includes/schema.inc
+++ b/core/includes/schema.inc
@@ -36,24 +36,7 @@
  *   If TRUE, the schema will be rebuilt instead of retrieved from the cache.
  */
 function drupal_get_schema($table = NULL, $rebuild = FALSE) {
-  static $schema;
-
-  if ($rebuild || !isset($table)) {
-    $schema = drupal_get_complete_schema($rebuild);
-  }
-  elseif (!isset($schema)) {
-    $schema = new SchemaCache();
-  }
-
-  if (!isset($table)) {
-    return $schema;
-  }
-  if (isset($schema[$table])) {
-    return $schema[$table];
-  }
-  else {
-    return FALSE;
-  }
+  return \Drupal::service('schema')->getSchema($table, $rebuild);
 }
 
 /**
@@ -66,45 +49,7 @@ function drupal_get_schema($table = NULL, $rebuild = FALSE) {
  *   If TRUE, the schema will be rebuilt instead of retrieved from the cache.
  */
 function drupal_get_complete_schema($rebuild = FALSE) {
-  static $schema;
-
-  if (!isset($schema) || $rebuild) {
-    // Try to load the schema from cache.
-    if (!$rebuild && $cached = cache()->get('schema')) {
-      $schema = $cached->data;
-    }
-    // Otherwise, rebuild the schema cache.
-    else {
-      $schema = array();
-      // Load the .install files to get hook_schema.
-      \Drupal::moduleHandler()->loadAllIncludes('install');
-
-      require_once __DIR__ . '/common.inc';
-      // Invoke hook_schema for all modules.
-      foreach (\Drupal::moduleHandler()->getImplementations('schema') as $module) {
-        // Cast the result of hook_schema() to an array, as a NULL return value
-        // would cause array_merge() to set the $schema variable to NULL as well.
-        // That would break modules which use $schema further down the line.
-        $current = (array) module_invoke($module, 'schema');
-        // Set 'module' and 'name' keys for each table, and remove descriptions,
-        // as they needlessly slow down cache()->get() for every single request.
-        _drupal_schema_initialize($current, $module);
-        $schema = array_merge($schema, $current);
-      }
-      drupal_alter('schema', $schema);
-
-      if ($rebuild) {
-        cache()->deleteTags(array('schema' => TRUE));
-      }
-      // If the schema is empty, avoid saving it: some database engines require
-      // the schema to perform queries, and this could lead to infinite loops.
-      if (!empty($schema) && (drupal_get_bootstrap_phase() == DRUPAL_BOOTSTRAP_FULL)) {
-        cache()->set('schema', $schema, CacheBackendInterface::CACHE_PERMANENT, array('schema' => TRUE));
-      }
-    }
-  }
-
-  return $schema;
+  return \Drupal::service('schema')->getCompleteSchema($rebuild);
 }
 
 /**
@@ -118,36 +63,7 @@ function drupal_get_complete_schema($rebuild = FALSE) {
  *   version. Otherwise, FALSE.
  */
 function drupal_get_schema_versions($module) {
-  $updates = &drupal_static(__FUNCTION__, NULL);
-  if (!isset($updates[$module])) {
-    $updates = array();
-    foreach (\Drupal::moduleHandler()->getModuleList() as $loaded_module => $filename) {
-      $updates[$loaded_module] = array();
-    }
-
-    // Prepare regular expression to match all possible defined hook_update_N().
-    $regexp = '/^(?<module>.+)_update_(?<version>\d+)$/';
-    $functions = get_defined_functions();
-    // Narrow this down to functions ending with an integer, since all
-    // hook_update_N() functions end this way, and there are other
-    // possible functions which match '_update_'. We use preg_grep() here
-    // instead of foreaching through all defined functions, since the loop
-    // through all PHP functions can take significant page execution time
-    // and this function is called on every administrative page via
-    // system_requirements().
-    foreach (preg_grep('/_\d+$/', $functions['user']) as $function) {
-      // If this function is a module update function, add it to the list of
-      // module updates.
-      if (preg_match($regexp, $function, $matches)) {
-        $updates[$matches['module']][] = $matches['version'];
-      }
-    }
-    // Ensure that updates are applied in numerical order.
-    foreach ($updates as &$module_updates) {
-      sort($module_updates, SORT_NUMERIC);
-    }
-  }
-  return empty($updates[$module]) ? FALSE : $updates[$module];
+  return \Drupal::service('schema')->getSchemaVersions($module);
 }
 
 /**
@@ -166,24 +82,7 @@ function drupal_get_schema_versions($module) {
  *   module is not installed.
  */
 function drupal_get_installed_schema_version($module, $reset = FALSE, $array = FALSE) {
-  static $versions = array();
-
-  if ($reset) {
-    $versions = array();
-  }
-
-  if (!$versions) {
-    if (!$versions = \Drupal::keyValue('system.schema')->getAll()) {
-      $versions = array();
-    }
-  }
-
-  if ($array) {
-    return $versions;
-  }
-  else {
-    return isset($versions[$module]) ? $versions[$module] : SCHEMA_UNINSTALLED;
-  }
+  return \Drupal::service('schema')->getInstalledSchemaVersion($module, $reset, $array);
 }
 
 /**
@@ -195,9 +94,7 @@ function drupal_get_installed_schema_version($module, $reset = FALSE, $array = F
  *   The new schema version.
  */
 function drupal_set_installed_schema_version($module, $version) {
-  \Drupal::keyValue('system.schema')->set($module, $version);
-  // Reset the static cache of module schema versions.
-  drupal_get_installed_schema_version(NULL, TRUE);
+  \Drupal::service('schema')->setInstalledSchemaVersion($module, $version);
 }
 
 /**
@@ -211,12 +108,7 @@ function drupal_set_installed_schema_version($module, $version) {
  *   The module for which the tables will be created.
  */
 function drupal_install_schema($module) {
-  $schema = drupal_get_schema_unprocessed($module);
-  _drupal_schema_initialize($schema, $module, FALSE);
-
-  foreach ($schema as $name => $table) {
-    db_create_table($name, $table);
-  }
+  \Drupal::service('schema')->installSchema($module);
 }
 
 /**
@@ -236,14 +128,7 @@ function drupal_install_schema($module) {
  *      \Drupal\Component\Utility\String::checkPlain().
  */
 function drupal_uninstall_schema($module) {
-  $schema = drupal_get_schema_unprocessed($module);
-  _drupal_schema_initialize($schema, $module, FALSE);
-
-  foreach ($schema as $table) {
-    if (db_table_exists($table['name'])) {
-      db_drop_table($table['name']);
-    }
-  }
+  \Drupal::service('schema')->uninstallSchema($module);
 }
 
 /**
@@ -271,51 +156,7 @@ function drupal_uninstall_schema($module) {
  *   is returned.
  */
 function drupal_get_schema_unprocessed($module, $table = NULL) {
-  // Load the .install file to get hook_schema.
-  module_load_install($module);
-  $schema = module_invoke($module, 'schema');
-
-  if (isset($table)) {
-    if (isset($schema[$table])) {
-      return $schema[$table];
-    }
-    return array();
-  }
-  elseif (!empty($schema)) {
-    return $schema;
-  }
-  return array();
-}
-
-/**
- * Fills in required default values for table definitions from hook_schema().
- *
- * @param array $schema
- *   The schema definition array as it was returned by the module's
- *   hook_schema().
- * @param string $module
- *   The module for which hook_schema() was invoked.
- * @param bool $remove_descriptions
- *   (optional) Whether to additionally remove 'description' keys of all tables
- *   and fields to improve performance of serialize() and unserialize().
- *   Defaults to TRUE.
- */
-function _drupal_schema_initialize(&$schema, $module, $remove_descriptions = TRUE) {
-  // Set the name and module key for all tables.
-  foreach ($schema as $name => &$table) {
-    if (empty($table['module'])) {
-      $table['module'] = $module;
-    }
-    if (!isset($table['name'])) {
-      $table['name'] = $name;
-    }
-    if ($remove_descriptions) {
-      unset($table['description']);
-      foreach ($table['fields'] as &$field) {
-        unset($field['description']);
-      }
-    }
-  }
+  return \Drupal::service('schema')->getSchemaUnprocessed($module, $table);
 }
 
 /**
@@ -332,7 +173,7 @@ function _drupal_schema_initialize(&$schema, $module, $remove_descriptions = TRU
  *   An array of fields.
  */
 function drupal_schema_fields_sql($table, $prefix = NULL) {
-  if (!$schema = drupal_get_schema($table)) {
+  if (!$schema = \Drupal::service('schema')->getSchema($table)) {
     return array();
   }
   $fields = array_keys($schema['fields']);
@@ -526,19 +367,7 @@ function drupal_write_record($table, &$record, $primary_keys = array()) {
  *   The converted value.
  */
 function drupal_schema_get_field_value(array $info, $value) {
-  // Preserve legal NULL values.
-  if (isset($value) || !empty($info['not null'])) {
-    if ($info['type'] == 'int' || $info['type'] == 'serial') {
-      $value = (int) $value;
-    }
-    elseif ($info['type'] == 'float') {
-      $value = (float) $value;
-    }
-    else {
-      $value = (string) $value;
-    }
-  }
-  return $value;
+  return \Drupal::service('schema')->getSchemaFieldValue($info, $value);
 }
 
 /**
diff --git a/core/includes/update.inc b/core/includes/update.inc
index 186255d..460d5f1 100644
--- a/core/includes/update.inc
+++ b/core/includes/update.inc
@@ -93,7 +93,6 @@ function update_check_incompatibility($name, $type = 'module') {
  */
 function update_prepare_d8_bootstrap() {
   include_once __DIR__ . '/install.inc';
-  include_once __DIR__ . '/schema.inc';
   // Bootstrap to configuration.
   drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION);
 
@@ -153,7 +152,7 @@ function update_prepare_d8_bootstrap() {
   // to happen AFTER the database bootstraps because of
   // drupal_get_installed_schema_version().
   try {
-    $system_schema = drupal_get_installed_schema_version('system');
+    $system_schema = \Drupal::service('schema')->getInstalledSchemaVersion('system');
   }
   catch (\Exception $e) {
     $system_schema = db_query('SELECT schema_version FROM {system} WHERE name = :system', array(':system' => 'system'))->fetchField();
@@ -674,7 +673,7 @@ function update_prepare_d8_language() {
  * made which make it impossible to continue using the prior version.
  */
 function update_fix_d8_requirements() {
-  if (drupal_get_installed_schema_version('system') < 8000 && !update_variable_get('update_d8_requirements', FALSE)) {
+  if (\Drupal::Service('schema')->getInstalledSchemaVersion('system') < 8000 && !update_variable_get('update_d8_requirements', FALSE)) {
 
     // Make sure that file.module is enabled as it is required for the user
     // picture upgrade path.
@@ -841,7 +840,7 @@ function update_do_one($module, $number, $dependency_map, &$context) {
 
   // Record the schema update if it was completed successfully.
   if ($context['finished'] == 1 && empty($ret['#abort'])) {
-    drupal_set_installed_schema_version($module, $number);
+    \Drupal::service('schema')->setInstalledSchemaVersion($module, $number);
   }
 
   $context['message'] = 'Updating ' . String::checkPlain($module) . ' module';
diff --git a/core/lib/Drupal/Core/Extension/ModuleHandler.php b/core/lib/Drupal/Core/Extension/ModuleHandler.php
index 92cf2a4..bb0c306 100644
--- a/core/lib/Drupal/Core/Extension/ModuleHandler.php
+++ b/core/lib/Drupal/Core/Extension/ModuleHandler.php
@@ -613,8 +613,9 @@ public function install(array $module_list, $enable_dependencies = TRUE) {
           $kernel->updateModules($module_filenames, $module_filenames);
         }
 
+        $schema = \Drupal::service('schema');
         // Refresh the schema to include it.
-        drupal_get_schema(NULL, TRUE);
+        $schema->getSchema(NULL, TRUE);
         // Update the theme registry to include it.
         drupal_theme_rebuild();
 
@@ -625,11 +626,11 @@ public function install(array $module_list, $enable_dependencies = TRUE) {
         entity_info_cache_clear();
 
         // Now install the module's schema if necessary.
-        drupal_install_schema($module);
+        $schema->installSchema($module);
 
         // Set the schema version to the number of the last update provided
         // by the module.
-        $versions = drupal_get_schema_versions($module);
+        $versions = $schema->getSchemaVersions($module);
         $version = $versions ? max($versions) : SCHEMA_INSTALLED;
 
         // Install default configuration of the module.
@@ -641,7 +642,7 @@ public function install(array $module_list, $enable_dependencies = TRUE) {
         if ($last_removed = $this->invoke($module, 'update_last_removed')) {
           $version = max($version, $last_removed);
         }
-        drupal_set_installed_schema_version($module, $version);
+        $schema->setInstalledSchemaVersion($module, $version);
 
         // Record the fact that it was installed.
         $modules_installed[] = $module;
@@ -714,6 +715,7 @@ public function uninstall(array $module_list, $uninstall_dependents = TRUE) {
     // the module already, which means that it might be loaded, but not
     // necessarily installed.
     $schema_store = \Drupal::keyValue('system.schema');
+    $schema = \Drupal::service('schema');
     foreach ($module_list as $module) {
       // Allow modules to react prior to the uninstallation of a module.
       $this->invokeAll('module_preuninstall', array($module));
@@ -721,7 +723,7 @@ public function uninstall(array $module_list, $uninstall_dependents = TRUE) {
       // Uninstall the module.
       module_load_install($module);
       $this->invoke($module, 'uninstall');
-      drupal_uninstall_schema($module);
+      $schema->uninstallSchema($module);
 
       // Remove all configuration belonging to the module.
       config_uninstall_default_config('module', $module);
@@ -757,7 +759,8 @@ public function uninstall(array $module_list, $uninstall_dependents = TRUE) {
 
       $schema_store->delete($module);
     }
-    drupal_get_installed_schema_version(NULL, TRUE);
+
+    $schema->getInstalledSchemaVersion(NULL, TRUE);
 
     // Let other modules react.
     $this->invokeAll('modules_uninstalled', array($module_list));
diff --git a/core/lib/Drupal/Core/Schema/Schema.php b/core/lib/Drupal/Core/Schema/Schema.php
new file mode 100644
index 0000000..a9fc545
--- /dev/null
+++ b/core/lib/Drupal/Core/Schema/Schema.php
@@ -0,0 +1,404 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Schema\Schema.
+ */
+
+namespace Drupal\Core\Schema;
+
+use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\KeyValueStore\KeyValueFactory;
+use Drupal\Core\Utility\SchemaCache;
+
+class Schema {
+
+  /**
+   * Indicates that a module has not been installed yet.
+   */
+  const SCHEMA_UNINSTALLED = -1;
+
+  /**
+   * Indicates that a module has been installed.
+   */
+  const SCHEMA_INSTALLED = 0;
+
+  /**
+   * Statically cached schema data.
+   *
+   * @var array|\Drupal\Core\Utility\SchemaCache
+   */
+  protected $schema;
+
+  /**
+   * Statically cached complete schema data.
+   *
+   * @var array
+   */
+  protected $completeSchema;
+
+  /**
+   * A static cache of schema versions per module.
+   *
+   * @var array
+   */
+  protected $updates;
+
+  /**
+   * A static cache of current module schema versions.
+   *
+   * @var array
+   */
+  protected $versions;
+
+  /**
+   * The module handler.
+   *
+   * @var \Drupal\Core\Extension\ModuleHandlerInterface
+   */
+  protected $moduleHandler;
+
+  /**
+   * The cache backend.
+   *
+   * @var \Drupal\Core\Cache\CacheBackendInterface
+   */
+  protected $cacheBackend;
+
+  /**
+   * @var \Drupal\Core\KeyValueStore\KeyValueStoreInterface
+   */
+  protected $keyValue;
+
+  /**
+   * Constructs a Schema object.
+   */
+  public function __construct(ModuleHandlerInterface $module_handler, CacheBackendInterface $cache_backend, KeyValueFactory $keyvalue) {
+    $this->moduleHandler = $module_handler;
+    $this->cacheBackend = $cache_backend;
+    $this->keyValue = $keyvalue->get('system.schema');
+  }
+
+  /**
+   * Gets the schema definition of a table, or the whole database schema.
+   *
+   * The returned schema will include any modifications made by any
+   * module that implements hook_schema_alter().
+   *
+   * @param string $table
+   *   The name of the table. If not given, the schema of all tables is returned.
+   * @param bool $rebuild
+   *   If TRUE, the schema will be rebuilt instead of retrieved from the cache.
+   */
+  public function getSchema($table = NULL, $rebuild = FALSE) {
+    if ($rebuild || !isset($table)) {
+      $this->schema = $this->getCompleteSchema($rebuild);
+    }
+    elseif (!isset($this->schema)) {
+      $this->schema = new SchemaCache();
+    }
+
+    if (!isset($table)) {
+      return $this->schema;
+    }
+    if (isset($this->schema[$table])) {
+      return $this->schema[$table];
+    }
+    else {
+      return FALSE;
+    }
+  }
+
+  /**
+   * Gets the whole database schema.
+   *
+   * The returned schema will include any modifications made by any
+   * module that implements hook_schema_alter().
+   *
+   * @param bool $rebuild
+   *   If TRUE, the schema will be rebuilt instead of retrieved from the cache.
+   */
+  public function getCompleteSchema($rebuild = FALSE) {
+    if (!isset($this->completeSchema) || $rebuild) {
+      // Try to load the schema from cache.
+      if (!$rebuild && ($cached = $this->cacheBackend->get('schema'))) {
+        $this->completeSchema = $cached->data;
+      }
+      // Otherwise, rebuild the schema cache.
+      else {
+        $this->completeSchema = array();
+        // Load the .install files to get hook_schema.
+        $this->moduleHandler->loadAllIncludes('install');
+
+        // Invoke hook_schema for all modules.
+        foreach ($this->moduleHandler->getImplementations('schema') as $module) {
+          // Cast the result of hook_schema() to an array, as a NULL return value
+          // would cause array_merge() to set the $schema variable to NULL as well.
+          // That would break modules which use $schema further down the line.
+          $current = (array) $this->moduleHandler->invoke($module, 'schema');
+          // Set 'module' and 'name' keys for each table, and remove descriptions,
+          // as they needlessly slow down cache()->get() for every single request.
+          $this->initialize($current, $module);
+          $this->completeSchema = array_merge($this->completeSchema, $current);
+        }
+
+        $this->moduleHandler->alter('schema', $this->completeSchema);
+
+        if ($rebuild) {
+          $this->cacheBackend->deleteTags(array('schema' => TRUE));
+        }
+        // If the schema is empty, avoid saving it: some database engines require
+        // the schema to perform queries, and this could lead to infinite loops.
+        if (!empty($this->completeSchema) && (drupal_get_bootstrap_phase() == DRUPAL_BOOTSTRAP_FULL)) {
+          $this->cacheBackend->set('schema', $this->completeSchema, CacheBackendInterface::CACHE_PERMANENT, array('schema' => TRUE));
+        }
+      }
+    }
+
+    return $this->completeSchema;
+  }
+
+  /**
+   * Returns an array of available schema versions for a module.
+   *
+   * @param string $module
+   *   A module name.
+   *
+   * @return array|bool
+   *   If the module has updates, an array of available updates sorted by
+   *   version. Otherwise, FALSE.
+   */
+  public function getSchemaVersions($module) {
+    if (!isset($this->updates[$module])) {
+      $this->updates = array();
+      foreach ($this->moduleHandler->getModuleList() as $loaded_module => $filename) {
+        $this->updates[$loaded_module] = array();
+      }
+
+      // Prepare regular expression to match all possible defined hook_update_N().
+      $regexp = '/^(?<module>.+)_update_(?<version>\d+)$/';
+      $functions = get_defined_functions();
+      // Narrow this down to functions ending with an integer, since all
+      // hook_update_N() functions end this way, and there are other
+      // possible functions which match '_update_'. We use preg_grep() here
+      // instead of foreaching through all defined functions, since the loop
+      // through all PHP functions can take significant page execution time
+      // and this function is called on every administrative page via
+      // system_requirements().
+      foreach (preg_grep('/_\d+$/', $functions['user']) as $function) {
+        // If this function is a module update function, add it to the list of
+        // module updates.
+        if (preg_match($regexp, $function, $matches)) {
+          $this->updates[$matches['module']][] = $matches['version'];
+        }
+      }
+      // Ensure that updates are applied in numerical order.
+      foreach ($this->updates as &$module_updates) {
+        sort($module_updates, SORT_NUMERIC);
+      }
+    }
+
+    return empty($this->updates[$module]) ? FALSE : $this->updates[$module];
+  }
+
+  /**
+   * Returns the currently installed schema version for a module.
+   *
+   * @param string $module
+   *   A module name.
+   * @param bool $reset
+   *   Set to TRUE after installing or uninstalling an extension.
+   * @param bool $array
+   *   Set to TRUE if you want to get information about all modules in the
+   *   system.
+   *
+   * @return string|int
+   *   The currently installed schema version, or SCHEMA_UNINSTALLED if the
+   *   module is not installed.
+   */
+  public function getInstalledSchemaVersion($module, $reset = FALSE, $array = FALSE) {
+    if ($reset) {
+      $this->versions = array();
+    }
+
+    if (!$this->versions) {
+      if (!$this->versions = $this->keyValue->getAll()) {
+        $this->versions = array();
+      }
+    }
+
+    if ($array) {
+      return $this->versions;
+    }
+    else {
+      return isset($this->versions[$module]) ? $this->versions[$module] : static::SCHEMA_UNINSTALLED;
+    }
+  }
+
+  /**
+   * Updates the installed version information for a module.
+   *
+   * @param string $module
+   *   A module name.
+   * @param string $version
+   *   The new schema version.
+   */
+  public function setInstalledSchemaVersion($module, $version) {
+    $this->keyValue->set($module, $version);
+    // Reset the static cache of module schema versions.
+    $this->getInstalledSchemaVersion(NULL, TRUE);
+  }
+
+  /**
+   * Creates all tables defined in a module's hook_schema().
+   *
+   * Note: This function does not pass the module's schema through
+   * hook_schema_alter(). The module's tables will be created exactly as the
+   * module defines them.
+   *
+   * @param string $module
+   *   The module for which the tables will be created.
+   */
+  public function installSchema($module) {
+    $schema = $this->getSchemaUnprocessed($module);
+    $this->initialize($schema, $module, FALSE);
+
+    foreach ($schema as $name => $table) {
+      db_create_table($name, $table);
+    }
+  }
+
+  /**
+   * Removes all tables defined in a module's hook_schema().
+   *
+   * Note: This function does not pass the module's schema through
+   * hook_schema_alter(). The module's tables will be created exactly as the
+   * module defines them.
+   *
+   * @param string $module
+   *   The module for which the tables will be removed.
+   *
+   * @return array
+   *   An array of arrays with the following key/value pairs:
+   *    - success: a boolean indicating whether the query succeeded.
+   *    - query: the SQL query(s) executed, passed through
+   *      \Drupal\Component\Utility\String::checkPlain().
+   */
+  public function uninstallSchema($module) {
+    $schema = $this->getSchemaUnprocessed($module);
+    $this->initialize($schema, $module, FALSE);
+
+    foreach ($schema as $table) {
+      if (db_table_exists($table['name'])) {
+        db_drop_table($table['name']);
+      }
+    }
+  }
+
+  /**
+   * Returns the unprocessed and unaltered version of a module's schema.
+   *
+   * Use this function only if you explicitly need the original
+   * specification of a schema, as it was defined in a module's
+   * hook_schema(). No additional default values will be set,
+   * hook_schema_alter() is not invoked and these unprocessed
+   * definitions won't be cached.
+   *
+   * This function can be used to retrieve a schema specification in
+   * hook_schema(), so it allows you to derive your tables from existing
+   * specifications.
+   *
+   * It is also used by drupal_install_schema() and
+   * drupal_uninstall_schema() to ensure that a module's tables are
+   * created exactly as specified without any changes introduced by a
+   * module that implements hook_schema_alter().
+   *
+   * @param string $module
+   *   The module to which the table belongs.
+   * @param string $table
+   *   The name of the table. If not given, the module's complete schema
+   *   is returned.
+   */
+  public function getSchemaUnprocessed($module, $table = NULL) {
+    // Load the .install file to get hook_schema.
+    $this->moduleHandler->loadInclude($module, 'install');
+    $schema = $this->moduleHandler->invoke($module, 'schema');
+
+    if (isset($table)) {
+      if (isset($schema[$table])) {
+        return $schema[$table];
+      }
+      return array();
+    }
+    elseif (!empty($schema)) {
+      return $schema;
+    }
+
+    return array();
+  }
+
+  /**
+   * Typecasts values to proper datatypes.
+   *
+   * MySQL PDO silently casts, e.g. FALSE and '' to 0, when inserting the value
+   * into an integer column, but PostgreSQL PDO does not. Look up the schema
+   * information and use that to correctly typecast the value.
+   *
+   * @param array $info
+   *   An array describing the schema field info.
+   * @param mixed $value
+   *   The value to be converted.
+   *
+   * @return mixed
+   *   The converted value.
+   */
+  public function getSchemaFieldValue(array $info, $value) {
+    // Preserve legal NULL values.
+    if (isset($value) || !empty($info['not null'])) {
+      if ($info['type'] == 'int' || $info['type'] == 'serial') {
+        $value = (int) $value;
+      }
+      elseif ($info['type'] == 'float') {
+        $value = (float) $value;
+      }
+      else {
+        $value = (string) $value;
+      }
+    }
+
+    return $value;
+  }
+
+  /**
+   * Fills in required default values for table definitions from hook_schema().
+   *
+   * @param array $schema
+   *   The schema definition array as it was returned by the module's
+   *   hook_schema().
+   * @param string $module
+   *   The module for which hook_schema() was invoked.
+   * @param bool $remove_descriptions
+   *   (optional) Whether to additionally remove 'description' keys of all tables
+   *   and fields to improve performance of serialize() and unserialize().
+   *   Defaults to TRUE.
+   */
+  protected function initialize(&$schema, $module, $remove_descriptions = TRUE) {
+    // Set the name and module key for all tables.
+    foreach ($schema as $name => &$table) {
+      if (empty($table['module'])) {
+        $table['module'] = $module;
+      }
+      if (!isset($table['name'])) {
+        $table['name'] = $name;
+      }
+      if ($remove_descriptions) {
+        unset($table['description']);
+        foreach ($table['fields'] as &$field) {
+          unset($field['description']);
+        }
+      }
+    }
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Utility/SchemaCache.php b/core/lib/Drupal/Core/Utility/SchemaCache.php
index 4e3bdd4..ce9ebee 100644
--- a/core/lib/Drupal/Core/Utility/SchemaCache.php
+++ b/core/lib/Drupal/Core/Utility/SchemaCache.php
@@ -27,7 +27,7 @@ public function __construct() {
    * Implements CacheArray::resolveCacheMiss().
    */
   protected function resolveCacheMiss($offset) {
-    $complete_schema = drupal_get_complete_schema();
+    $complete_schema = \Drupal::service('schema')->getCompleteSchema();
     $value = isset($complete_schema[$offset]) ? $complete_schema[$offset] :  NULL;
     $this->storage[$offset] = $value;
     $this->persist($offset);
