diff --git a/core/lib/Drupal/Core/Entity/ContentEntityDatabaseStorage.php b/core/lib/Drupal/Core/Entity/ContentEntityDatabaseStorage.php
index e77d74a..1ff16ed 100644
--- a/core/lib/Drupal/Core/Entity/ContentEntityDatabaseStorage.php
+++ b/core/lib/Drupal/Core/Entity/ContentEntityDatabaseStorage.php
@@ -9,10 +9,11 @@
 
 use Drupal\Core\Database\Connection;
 use Drupal\Core\Database\Database;
+use Drupal\Core\Database\SchemaObjectExistsException;
+use Drupal\Core\Database\Transaction;
 use Drupal\Core\Entity\Query\QueryInterface;
 use Drupal\Core\Entity\Schema\ContentEntitySchemaHandler;
 use Drupal\Core\Entity\Schema\ContentEntitySchemaHandlerInterface;
-use Drupal\Core\Field\FieldDefinitionInterface;
 use Drupal\Core\Field\FieldStorageDefinitionInterface;
 use Drupal\Core\Language\Language;
 use Drupal\field\FieldInfo;
@@ -248,6 +249,34 @@ public function getRevisionDataTable() {
   }
 
   /**
+   * Check if the database schema has been installed, and install it if not.
+   *
+   * @todo Make this protected in https://drupal.org/node/2249113
+   *
+   * @return bool
+   *   TRUE if the database schema exists or could be created successfully,
+   *   FALSE otherwise.
+   */
+  public function ensureSchemaExists() {
+    try {
+      $schema_service = $this->database->schema();
+      foreach ($this->getSchema() as $table_name => $table_schema) {
+        if (!$schema_service->tableExists($table_name)) {
+          $schema_service->createTable($table_name, $table_schema);
+        }
+      }
+      return TRUE;
+    }
+    // If another process has already created the cache table, attempting to
+    // recreate it will throw an exception. In this case just catch the
+    // exception and do nothing.
+    catch (SchemaObjectExistsException $e) {
+      return TRUE;
+    }
+    return FALSE;
+  }
+
+  /**
    * {@inheritdoc}
    */
   public function getSchema() {
@@ -303,9 +332,6 @@ public function getTableMapping() {
       // @todo Rename 'log' to 'revision_log' in
       //   https://drupal.org/node/2248991.
       $revision_metadata_fields = array_intersect(array('revision_timestamp', 'revision_uid', 'log'), $all_fields);
-      $revisionable_filter_callback = function (FieldDefinitionInterface $definition) {
-        return $definition->isRevisionable();
-      };
 
       switch ($this->getTableLayout()) {
         // The base layout stores all the base field values in the base table.
@@ -403,13 +429,20 @@ protected function getColumnMapping($field_names) {
    * {@inheritdoc}
    */
   protected function doLoadMultiple(array $ids = NULL) {
+    try {
       // Build and execute the query.
-    $records = $this
-      ->buildQuery($ids)
-      ->execute()
-      ->fetchAllAssoc($this->idKey);
+      $records = $this
+        ->buildQuery($ids)
+        ->execute()
+        ->fetchAllAssoc($this->idKey);
+
+      return $this->mapFromStorageRecords($records);
+    }
+    catch (\Exception $e) {
+      // If the schema does not exist, there are no entities to load.
+      return array();
+    }
 
-    return $this->mapFromStorageRecords($records);
   }
 
   /**
@@ -700,6 +733,8 @@ public function delete(array $entities) {
   protected function doDelete($entities) {
     $ids = array_keys($entities);
 
+    // Because deleting entities requires loading them beforehand, we do not
+    // need to care about the schema not existing here.
     $this->database->delete($this->entityType->getBaseTable())
       ->condition($this->idKey, $ids)
       ->execute();
@@ -735,8 +770,9 @@ protected function doDelete($entities) {
    * {@inheritdoc}
    */
   public function save(EntityInterface $entity) {
-    $transaction = $this->database->startTransaction();
-    try {
+    $try_again = FALSE;
+
+    $do_save = function (EntityInterface $entity) {
       // Sync the changes made in the fields array to the internal values array.
       $entity->updateOriginalValues();
 
@@ -745,11 +781,33 @@ public function save(EntityInterface $entity) {
       // Ignore slave server temporarily.
       db_ignore_slave();
       return $return;
-    }
-    catch (\Exception $e) {
+    };
+
+    $rethrow_exception = function (\Exception $e, Transaction $transaction) {
       $transaction->rollback();
       watchdog_exception($this->entityTypeId, $e);
       throw new EntityStorageException($e->getMessage(), $e->getCode(), $e);
+    };
+
+    $transaction = $this->database->startTransaction();
+    try {
+      return $do_save($entity);
+    }
+    catch (\Exception $e) {
+      // Try to create the schema.
+      if (!$try_again = $this->ensureSchemaExists()) {
+        $rethrow_exception($e, $transaction);
+      }
+    }
+
+    // If the schema has just been created, try the save operation again.
+    if ($try_again) {
+      try {
+        return $do_save($entity);
+      }
+      catch (\Exception $e) {
+        $rethrow_exception($e, $transaction);
+      }
     }
   }
 
diff --git a/core/lib/Drupal/Core/Entity/Query/Sql/Query.php b/core/lib/Drupal/Core/Entity/Query/Sql/Query.php
index cf8eb39..df64f45 100644
--- a/core/lib/Drupal/Core/Entity/Query/Sql/Query.php
+++ b/core/lib/Drupal/Core/Entity/Query/Sql/Query.php
@@ -247,13 +247,19 @@ protected function finish() {
    *   Returns the query result as entity IDs.
    */
   protected function result() {
-    if ($this->count) {
-      return $this->sqlQuery->countQuery()->execute()->fetchField();
+    try {
+      if ($this->count) {
+        return $this->sqlQuery->countQuery()->execute()->fetchField();
+      }
+      // Return a keyed array of results. The key is either the revision_id or
+      // the entity_id depending on whether the entity type supports revisions.
+      // The value is always the entity id.
+      return $this->sqlQuery->execute()->fetchAllKeyed();
+    }
+    catch (\Exception $e) {
+      // If the schema does not exist, there are no entity IDs to load.
+      return array();
     }
-    // Return a keyed array of results. The key is either the revision_id or
-    // the entity_id depending on whether the entity type supports revisions.
-    // The value is always the entity id.
-    return $this->sqlQuery->execute()->fetchAllKeyed();
   }
 
   /**
diff --git a/core/modules/entity/entity.api.php b/core/modules/entity/entity.api.php
deleted file mode 100644
index fac9a40..0000000
--- a/core/modules/entity/entity.api.php
+++ /dev/null
@@ -1,48 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains hooks provided by the Entity module.
- */
-
-/**
- * Allows to react the installation of entity schema.
- *
- * After modules have been installed Entity module checks for any new entity
- * types and installs the entity schema if the entity type's storage supports
- * automatic schema generation. This hook is invoked after the entity schema has
- * been installed.
- *
- * @param \Drupal\Core\Entity\EntityStorageInterface[]|\Drupal\Core\Entity\Schema\ContentEntitySchemaHandlerInterface[] $storages
- *   An array of entity storages of the entity types whose schemas have been
- *   installed keyed by entity type ID.
- */
-function hook_entity_schema_installed(array $storages) {
-  if (isset($storages['taxonomy_term'])) {
-    // Create a default forum so forum posts can be created.
-    $storages['taxonomy_term']->create(array(
-      'name' => t('General discussion'),
-      'description' => '',
-      'parent' => array(0),
-      'vid' => 'forums',
-      'forum_container' => 0,
-    ))->save();
-  }
-}
-
-/**
- * Allows to react the uninstallation of entity schema.
- *
- * After modules have been uninstalled Entity module checks for any removed
- * entity types and installs the entity schema if the entity type's storage
- * supports automatic schema generation. This hook is invoked after the entity
- * schema has been uninstalled.
- *
- * @param \Drupal\Core\Entity\EntityStorageInterface[]|\Drupal\Core\Entity\Schema\ContentEntitySchemaHandlerInterface[] $storages
- *   An array of entity storages of the entity types whose schemas have been
- *   uninstalled keyed by entity type ID.
- */
-function hook_entity_schema_uninstalled(array $storages) {
-  // Delete some derived data that depends on nodes.
-  \Drupal::state()->delete('mymodule.node_count');
-}
diff --git a/core/modules/entity/entity.module b/core/modules/entity/entity.module
index 625beab..1fa3852 100644
--- a/core/modules/entity/entity.module
+++ b/core/modules/entity/entity.module
@@ -9,7 +9,6 @@
  */
 
 use Drupal\Core\Config\Entity\ConfigEntityStorage;
-use Drupal\Core\Entity\Schema\ContentEntitySchemaHandlerInterface;
 
 /**
  * Implements hook_help().
@@ -100,77 +99,16 @@ function entity_entity_bundle_delete($entity_type_id, $bundle) {
 }
 
 /**
- * Implements hook_modules_installed().
- */
-function entity_modules_installed($modules) {
-  // Install entity type tables.
-  $entity_manager = \Drupal::entityManager();
-  $schema = \Drupal::database()->schema();
-  $definitions = $entity_manager->getDefinitions();
-  $storages = array();
-
-  foreach ($modules as $module) {
-    foreach ($definitions as $entity_type_id => $entity_type) {
-      if ($entity_type->getProvider() == $module) {
-        $storage = $entity_manager->getStorage($entity_type_id);
-        if ($storage instanceof ContentEntitySchemaHandlerInterface) {
-          foreach ($storage->getSchema() as $table_name => $table_schema) {
-            if (!$schema->tableExists($table_name)) {
-              $schema->createTable($table_name, $table_schema);
-              $storages[$entity_type_id] = $storage;
-            }
-          }
-        }
-      }
-    }
-  }
-
-  \Drupal::moduleHandler()->invokeAll('entity_schema_installed', array($storages));
-}
-
-/**
  * Implements hook_module_preuninstall().
  */
 function entity_module_preuninstall($module) {
-  $entity_manager = \Drupal::entityManager();
-  $definitions = $entity_manager->getDefinitions();
-
   // Clean up all entity bundles (including field instances) of every entity
   // type provided by the module that is being uninstalled.
-  foreach ($definitions as $entity_type_id => $entity_type) {
+  foreach (\Drupal::entityManager()->getDefinitions() as $entity_type_id => $entity_type) {
     if ($entity_type->getProvider() == $module) {
       foreach (array_keys(entity_get_bundles($entity_type_id)) as $bundle) {
         entity_invoke_bundle_hook('delete', $entity_type_id, $bundle);
       }
     }
   }
-
-  foreach ($definitions as $entity_type_id => $entity_type) {
-    if ($entity_type->getProvider() == $module) {
-      // Remove entity tables.
-      $storage = $entity_manager->getStorage($entity_type_id);
-      if ($storage instanceof ContentEntitySchemaHandlerInterface) {
-        foreach ($storage->getSchema() as $table_name => $table_schema) {
-          $GLOBALS['entity_schema_uninstall']['storages'][$entity_type_id] = $storage;
-          $GLOBALS['entity_schema_uninstall']['tables'][] = $table_name;
-        }
-      }
-    }
-  }
-}
-
-
-/**
- * Implements hook_modules_uninstalled().
- */
-function entity_modules_uninstalled($modules) {
-  if (!empty($GLOBALS['entity_schema_uninstall'])) {
-    $schema = \Drupal::database()->schema();
-    foreach ($GLOBALS['entity_schema_uninstall']['tables'] as $table_name) {
-      if ($schema->tableExists($table_name)) {
-        $schema->dropTable($table_name);
-      }
-    }
-    \Drupal::moduleHandler()->invokeAll('entity_schema_uninstalled', array($GLOBALS['entity_schema_uninstall']['storages']));
-  }
 }
diff --git a/core/modules/forum/forum.install b/core/modules/forum/forum.install
index 70b53b0..7f975e9 100644
--- a/core/modules/forum/forum.install
+++ b/core/modules/forum/forum.install
@@ -35,6 +35,16 @@ function forum_install() {
         ),
       ))->save();
 
+      // Create a default forum so forum posts can be created.
+      $term = entity_create('taxonomy_term', array(
+        'name' => t('General discussion'),
+        'description' => '',
+        'parent' => array(0),
+        'vid' => 'forums',
+        'forum_container' => 0,
+      ));
+      $term->save();
+
       // Create the instance on the bundle.
       entity_create('field_instance_config', array(
         'field_name' => 'taxonomy_forums',
@@ -58,6 +68,7 @@ function forum_install() {
           'weight' => 10,
         ))
         ->save();
+
       entity_get_display('node', 'forum', 'teaser')
         ->setComponent('taxonomy_forums', array(
           'type' => 'taxonomy_term_reference_link',
@@ -78,22 +89,6 @@ function forum_install() {
 }
 
 /**
- * Implements hook_entity_schema_installed().
- */
-function forum_entity_schema_installed(array $storages) {
-  if (isset($storages['taxonomy_term'])) {
-    // Create a default forum so forum posts can be created.
-    $storages['taxonomy_term']->create(array(
-      'name' => t('General discussion'),
-      'description' => '',
-      'parent' => array(0),
-      'vid' => 'forums',
-      'forum_container' => 0,
-    ))->save();
-  }
-}
-
-/**
  * Implements hook_uninstall().
  */
 function forum_uninstall() {
diff --git a/core/modules/user/lib/Drupal/user/Tests/UserInstallTest.php b/core/modules/user/lib/Drupal/user/Tests/UserInstallTest.php
index 25c61a8..de2f399 100644
--- a/core/modules/user/lib/Drupal/user/Tests/UserInstallTest.php
+++ b/core/modules/user/lib/Drupal/user/Tests/UserInstallTest.php
@@ -39,7 +39,7 @@ protected function setUp() {
     parent::setUp();
     $this->container->get('module_handler')->loadInclude('user', 'install');
     $this->installEntitySchema('user');
-    user_entity_schema_installed(array('user' => $this->container->get('entity.manager')->getStorage('user')));
+    user_install();
   }
 
 
diff --git a/core/modules/user/user.install b/core/modules/user/user.install
index 0640af2..b1c1064 100644
--- a/core/modules/user/user.install
+++ b/core/modules/user/user.install
@@ -5,8 +5,6 @@
  * Install, update and uninstall functions for the user module.
  */
 
-use Drupal\Core\Entity\ContentEntityDatabaseStorage;
-
 /**
  * Implements hook_schema().
  */
@@ -63,33 +61,33 @@ function user_schema() {
 }
 
 /**
- * Implements hook_entity_schema_installed().
+ * Implements hook_install().
  */
-function user_entity_schema_installed(array $storages) {
-  if (isset($storages['user'])) {
-    // Insert a row for the anonymous user.
-    db_insert('users')
-      ->fields(array(
-        'uid' => 0,
-        'uuid' => \Drupal::service('uuid')->generate(),
-        'name' => '',
-        'mail' => '',
-        'langcode' => \Drupal::languageManager()->getDefaultLanguage()->id,
-        ))
-      ->execute();
+function user_install() {
+  // @todo Clean this up in https://drupal.org/node/2249113
+  \Drupal::entityManager()->getStorage('user')->ensureSchemaExists();;
+  // Insert a row for the anonymous user.
+  db_insert('users')
+    ->fields(array(
+      'uid' => 0,
+      'uuid' => \Drupal::service('uuid')->generate(),
+      'name' => '',
+      'mail' => '',
+      'langcode' => \Drupal::languageManager()->getDefaultLanguage()->id,
+    ))
+    ->execute();
 
-    // We need some placeholders here as name and mail are uniques.
-    // This will be changed by the settings form in the installer.
-    db_insert('users')
-      ->fields(array(
-        'uid' => 1,
-        'uuid' => \Drupal::service('uuid')->generate(),
-        'name' => 'placeholder-for-uid-1',
-        'mail' => 'placeholder-for-uid-1',
-        'created' => REQUEST_TIME,
-        'status' => 1,
-        'langcode' => \Drupal::languageManager()->getDefaultLanguage()->id,
-      ))
-      ->execute();
-  }
+  // We need some placeholders here as name and mail are uniques.
+  // This will be changed by the settings form in the installer.
+  db_insert('users')
+    ->fields(array(
+      'uid' => 1,
+      'uuid' => \Drupal::service('uuid')->generate(),
+      'name' => 'placeholder-for-uid-1',
+      'mail' => 'placeholder-for-uid-1',
+      'created' => REQUEST_TIME,
+      'status' => 1,
+      'langcode' => \Drupal::languageManager()->getDefaultLanguage()->id,
+    ))
+    ->execute();
 }
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/pager/PagerPluginBase.php b/core/modules/views/lib/Drupal/views/Plugin/views/pager/PagerPluginBase.php
index d91e4bf..1d280c6 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/views/pager/PagerPluginBase.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/pager/PagerPluginBase.php
@@ -178,7 +178,14 @@ public function useCountQuery() {
    * itself being executed.
    */
   public function executeCountQuery(&$count_query) {
-    $this->total_items = $count_query->execute()->fetchField();
+    try {
+      $this->total_items = $count_query->execute()->fetchField();
+    }
+    catch (\Exception $e) {
+      // If the database schema does not exist, there are no items in the
+      // database.
+      $this->total_items = 0;
+    }
     if (!empty($this->options['offset'])) {
       $this->total_items -= $this->options['offset'];
     }
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/query/Sql.php b/core/modules/views/lib/Drupal/views/Plugin/views/query/Sql.php
index 175e7f4..ad47e15 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/views/query/Sql.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/query/Sql.php
@@ -1423,10 +1423,15 @@ function execute(ViewExecutable $view) {
           $query->range($offset, $limit);
         }
 
-        $result = $query->execute();
-        $result->setFetchMode(\PDO::FETCH_CLASS, 'Drupal\views\ResultRow');
+        try {
+          $result = $query->execute();
+          $result->setFetchMode(\PDO::FETCH_CLASS, 'Drupal\views\ResultRow');
+          $view->result = iterator_to_array($result);
+        }
+        catch (\Exception $e) {
+          $view->result = array();
+        }
 
-        $view->result = iterator_to_array($result);
 
         $view->pager->postExecute($view->result);
         $view->pager->updatePageInfo();
