diff --git a/core/lib/Drupal/Core/Routing/MatcherDumper.php b/core/lib/Drupal/Core/Routing/MatcherDumper.php
index 18e864f..568c0ad 100644
--- a/core/lib/Drupal/Core/Routing/MatcherDumper.php
+++ b/core/lib/Drupal/Core/Routing/MatcherDumper.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\Core\Routing;
 
+use Drupal\Core\Database\SchemaObjectExistsException;
+use Drupal\Core\Database\StatementInterface;
 use Drupal\Core\State\StateInterface;
 use Symfony\Component\Routing\RouteCollection;
 
@@ -14,6 +16,8 @@
 
 /**
  * Dumps Route information to a database table.
+ *
+ * @see \Drupal\Core\Routing\RouteProvider
  */
 class MatcherDumper implements MatcherDumperInterface {
 
@@ -97,7 +101,7 @@ public function dump(array $options = array()) {
     try {
       // We don't use truncate, because it is not guaranteed to be transaction
       // safe.
-      $this->connection->delete($this->tableName)->execute();
+      $this->safeDatabaseExecute($this->connection->delete($this->tableName));
 
       // Split the routes into chunks to avoid big INSERT queries.
       $route_chunks = array_chunk($this->routes->all(), 50, TRUE);
@@ -133,7 +137,7 @@ public function dump(array $options = array()) {
         }
 
         // Insert all new routes.
-        $insert->execute();
+        $this->safeDatabaseExecute($insert);
       }
 
 
@@ -161,4 +165,110 @@ public function getRoutes() {
     return $this->routes;
   }
 
+  /**
+   * Executes a query and ensures that the table exists.
+   *
+   * @param \Drupal\Core\Database\StatementInterface $query
+   *   The query to be executed.
+   *
+   * @return mixed
+   *   The result of the query.
+   *
+   * @throws \Exception
+   */
+  protected function safeDatabaseExecute(StatementInterface $query) {
+    try {
+      return $query->execute();
+    }
+    catch (\Exception $e) {
+      // If there was an exception, try to create the table.
+      if ($this->ensureTableExists()) {
+        return $query->execute();
+      }
+      // Some other failure that we can not recover from.
+      throw $e;
+    }
+  }
+
+  /**
+   * Checks if the tree table exists and create it if not.
+   *
+   * @return bool
+   *   TRUE if the table was created, FALSE otherwise.
+   */
+  protected function ensureTableExists() {
+    try {
+      if (!$this->connection->schema()->tableExists($this->tableName)) {
+        $this->connection->schema()->createTable($this->tableName, static::schemaDefinition());
+        return TRUE;
+      }
+    }
+    catch (SchemaObjectExistsException $e) {
+      // If another process has already created the config table, attempting to
+      // recreate it will throw an exception. In this case just catch the
+      // exception and do nothing.
+      return TRUE;
+    }
+    return FALSE;
+  }
+
+  /**
+   * Defines the schema for the router table.
+   *
+   * @return array
+   *   The schema API definition for the SQL storage table.
+   */
+  protected static function schemaDefinition() {
+    $schema = [
+      'description' => 'Maps paths to various callbacks (access, page and title)',
+      'fields' => [
+        'name' => [
+          'description' => 'Primary Key: Machine name of this route',
+          'type' => 'varchar',
+          'length' => 255,
+          'not null' => TRUE,
+          'default' => '',
+        ],
+        'path' => [
+          'description' => 'The path for this URI',
+          'type' => 'varchar',
+          'length' => 255,
+          'not null' => TRUE,
+          'default' => '',
+        ],
+        'pattern_outline' => [
+          'description' => 'The pattern',
+          'type' => 'varchar',
+          'length' => 255,
+          'not null' => TRUE,
+          'default' => '',
+        ],
+        'fit' => [
+          'description' => 'A numeric representation of how specific the path is.',
+          'type' => 'int',
+          'not null' => TRUE,
+          'default' => 0,
+        ],
+        'route' => [
+          'description' => 'A serialized Route object',
+          'type' => 'blob',
+          'size' => 'big',
+        ],
+        'number_parts' => [
+          'description' => 'Number of parts in this router path.',
+          'type' => 'int',
+          'not null' => TRUE,
+          'default' => 0,
+          'size' => 'small',
+        ],
+      ],
+      'indexes' => [
+        'pattern_outline_fit' => ['pattern_outline', 'fit'],
+      ],
+      'primary key' => ['name'],
+    ];
+
+    return $schema;
+  }
+
 }
diff --git a/core/modules/comment/src/Tests/CommentDefaultFormatterCacheTagsTest.php b/core/modules/comment/src/Tests/CommentDefaultFormatterCacheTagsTest.php
index 8747737f2d..c317c41 100644
--- a/core/modules/comment/src/Tests/CommentDefaultFormatterCacheTagsTest.php
+++ b/core/modules/comment/src/Tests/CommentDefaultFormatterCacheTagsTest.php
@@ -44,7 +44,6 @@ protected function setUp() {
     $this->installConfig(array('system', 'filter'));
 
     // Comment rendering generates links, so build the router.
-    $this->installSchema('system', array('router'));
     $this->container->get('router.builder')->rebuild();
 
     // Set up a field, so that the entity that'll be referenced bubbles up a
diff --git a/core/modules/field/src/Tests/FieldImportDeleteUninstallTest.php b/core/modules/field/src/Tests/FieldImportDeleteUninstallTest.php
index 188cceb..8d3bc7e 100644
--- a/core/modules/field/src/Tests/FieldImportDeleteUninstallTest.php
+++ b/core/modules/field/src/Tests/FieldImportDeleteUninstallTest.php
@@ -29,7 +29,6 @@ protected function setUp() {
     // Module uninstall requires the router and users_data tables.
     // @see drupal_flush_all_caches()
     // @see user_modules_uninstalled()
-    $this->installSchema('system', array('router'));
     $this->installSchema('user', array('users_data'));
   }
 
diff --git a/core/modules/hal/src/Tests/NormalizerTestBase.php b/core/modules/hal/src/Tests/NormalizerTestBase.php
index e7b59d6..2919eba 100644
--- a/core/modules/hal/src/Tests/NormalizerTestBase.php
+++ b/core/modules/hal/src/Tests/NormalizerTestBase.php
@@ -61,7 +61,7 @@
    */
   protected function setUp() {
     parent::setUp();
-    $this->installSchema('system', array('url_alias', 'router'));
+    $this->installSchema('system', array('url_alias'));
     $this->installEntitySchema('user');
     $this->installEntitySchema('entity_test');
     $this->installConfig(array('field', 'language'));
diff --git a/core/modules/options/src/Tests/OptionsFieldUnitTestBase.php b/core/modules/options/src/Tests/OptionsFieldUnitTestBase.php
index a254a0a..fcfe4f8 100644
--- a/core/modules/options/src/Tests/OptionsFieldUnitTestBase.php
+++ b/core/modules/options/src/Tests/OptionsFieldUnitTestBase.php
@@ -55,7 +55,6 @@
    */
   protected function setUp() {
     parent::setUp();
-    $this->installSchema('system', array('router'));
     $this->container->get('router.builder')->rebuild();
 
     $this->fieldStorageDefinition = array(
diff --git a/core/modules/rdf/src/Tests/Field/FieldRdfaTestBase.php b/core/modules/rdf/src/Tests/Field/FieldRdfaTestBase.php
index adddda1..6161326 100644
--- a/core/modules/rdf/src/Tests/Field/FieldRdfaTestBase.php
+++ b/core/modules/rdf/src/Tests/Field/FieldRdfaTestBase.php
@@ -63,7 +63,6 @@
   protected function setUp() {
     parent::setUp();
 
-    $this->installSchema('system', array('router'));
     \Drupal::service('router.builder')->rebuild();
   }
 
diff --git a/core/modules/system/src/Tests/Block/SystemMenuBlockTest.php b/core/modules/system/src/Tests/Block/SystemMenuBlockTest.php
index ce5b81b..7b47b69 100644
--- a/core/modules/system/src/Tests/Block/SystemMenuBlockTest.php
+++ b/core/modules/system/src/Tests/Block/SystemMenuBlockTest.php
@@ -83,7 +83,6 @@ protected function setUp() {
     parent::setUp();
     $this->installSchema('system', 'sequences');
     $this->installEntitySchema('user');
-    $this->installSchema('system', array('router'));
     $this->installEntitySchema('menu_link_content');
 
     $account = User::create([
diff --git a/core/modules/system/src/Tests/Element/PathElementFormTest.php b/core/modules/system/src/Tests/Element/PathElementFormTest.php
index dce7df6..2036532 100644
--- a/core/modules/system/src/Tests/Element/PathElementFormTest.php
+++ b/core/modules/system/src/Tests/Element/PathElementFormTest.php
@@ -42,7 +42,7 @@ class PathElementFormTest extends KernelTestBase implements FormInterface {
    */
   protected function setUp() {
     parent::setUp();
-    $this->installSchema('system', array('router', 'sequences'));
+    $this->installSchema('system', array('sequences'));
     $this->installEntitySchema('user');
     \Drupal::service('router.builder')->rebuild();
     /** @var \Drupal\user\RoleInterface $role */
diff --git a/core/modules/system/src/Tests/Entity/EntityBundleFieldTest.php b/core/modules/system/src/Tests/Entity/EntityBundleFieldTest.php
index 0866f7a..5aa55b2 100644
--- a/core/modules/system/src/Tests/Entity/EntityBundleFieldTest.php
+++ b/core/modules/system/src/Tests/Entity/EntityBundleFieldTest.php
@@ -41,7 +41,6 @@ class EntityBundleFieldTest extends EntityUnitTestBase  {
   protected function setUp() {
     parent::setUp();
     $this->installSchema('user', array('users_data'));
-    $this->installSchema('system', array('router'));
     $this->moduleHandler = $this->container->get('module_handler');
     $this->database = $this->container->get('database');
   }
diff --git a/core/modules/system/src/Tests/HttpKernel/StackKernelIntegrationTest.php b/core/modules/system/src/Tests/HttpKernel/StackKernelIntegrationTest.php
index 6018122..fbf7029 100644
--- a/core/modules/system/src/Tests/HttpKernel/StackKernelIntegrationTest.php
+++ b/core/modules/system/src/Tests/HttpKernel/StackKernelIntegrationTest.php
@@ -31,8 +31,6 @@ class StackKernelIntegrationTest extends KernelTestBase {
    */
   protected function setUp() {
     parent::setUp();
-
-    $this->installSchema('system', 'router');
     \Drupal::service('router.builder')->rebuild();
   }
 
diff --git a/core/modules/system/src/Tests/Menu/MenuLinkDefaultIntegrationTest.php b/core/modules/system/src/Tests/Menu/MenuLinkDefaultIntegrationTest.php
index 6078875..d96b29c 100644
--- a/core/modules/system/src/Tests/Menu/MenuLinkDefaultIntegrationTest.php
+++ b/core/modules/system/src/Tests/Menu/MenuLinkDefaultIntegrationTest.php
@@ -28,14 +28,6 @@ class MenuLinkDefaultIntegrationTest extends KernelTestBase {
   );
 
   /**
-   * {@inheritdoc}
-   */
-  protected function setUp() {
-    parent::setUp();
-    $this->installSchema('system', array('router'));
-  }
-
-  /**
    * Tests moving a static menu link without a specified menu to the root.
    */
   public function testMoveToRoot() {
diff --git a/core/modules/system/src/Tests/Menu/MenuLinkTreeTest.php b/core/modules/system/src/Tests/Menu/MenuLinkTreeTest.php
index 98b9685..3f78a27 100644
--- a/core/modules/system/src/Tests/Menu/MenuLinkTreeTest.php
+++ b/core/modules/system/src/Tests/Menu/MenuLinkTreeTest.php
@@ -52,7 +52,6 @@ class MenuLinkTreeTest extends KernelTestBase {
    */
   protected function setUp() {
     parent::setUp();
-    $this->installSchema('system', array('router'));
     $this->installEntitySchema('menu_link_content');
 
     $this->linkTree = $this->container->get('menu.link_tree');
diff --git a/core/modules/system/src/Tests/Routing/ExceptionHandlingTest.php b/core/modules/system/src/Tests/Routing/ExceptionHandlingTest.php
index 0d925b7..fa93a00 100644
--- a/core/modules/system/src/Tests/Routing/ExceptionHandlingTest.php
+++ b/core/modules/system/src/Tests/Routing/ExceptionHandlingTest.php
@@ -29,7 +29,6 @@ class ExceptionHandlingTest extends KernelTestBase {
   protected function setUp() {
     parent::setUp();
 
-    $this->installSchema('system', ['router']);
     \Drupal::service('router.builder')->rebuild();
   }
 
diff --git a/core/modules/system/src/Tests/Routing/UrlIntegrationTest.php b/core/modules/system/src/Tests/Routing/UrlIntegrationTest.php
index 66239c9..1d3f934 100644
--- a/core/modules/system/src/Tests/Routing/UrlIntegrationTest.php
+++ b/core/modules/system/src/Tests/Routing/UrlIntegrationTest.php
@@ -27,15 +27,6 @@ class UrlIntegrationTest extends KernelTestBase {
   public static $modules = array('user', 'router_test', 'system');
 
   /**
-   * {@inheritdoc}
-   */
-  protected function setUp() {
-    parent::setUp();
-
-    $this->installSchema('system', ['router']);
-  }
-
-  /**
    * Ensures that the access() method on \Drupal\Core\Url objects works.
    */
   public function testAccess() {
diff --git a/core/modules/system/system.install b/core/modules/system/system.install
index 868b2eb..21531fb 100644
--- a/core/modules/system/system.install
+++ b/core/modules/system/system.install
@@ -783,55 +783,6 @@ function system_schema() {
     ),
   );
 
-  $schema['router'] = array(
-    'description' => 'Maps paths to various callbacks (access, page and title)',
-    'fields' => array(
-      'name' => array(
-        'description' => 'Primary Key: Machine name of this route',
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => '',
-      ),
-      'path' => array(
-        'description' => 'The path for this URI',
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => '',
-      ),
-      'pattern_outline' => array(
-        'description' => 'The pattern',
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => '',
-      ),
-      'fit' => array(
-        'description' => 'A numeric representation of how specific the path is.',
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0,
-      ),
-      'route' => array(
-        'description' => 'A serialized Route object',
-        'type' => 'blob',
-        'size' => 'big',
-      ),
-      'number_parts' => array(
-        'description' => 'Number of parts in this router path.',
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0,
-        'size' => 'small',
-      ),
-    ),
-    'indexes' => array(
-      'pattern_outline_fit' => array('pattern_outline', 'fit'),
-    ),
-    'primary key' => array('name'),
-  );
-
   $schema['semaphore'] = array(
     'description' => 'Table for holding semaphores, locks, flags, etc. that cannot be stored as state since they must not be cached.',
     'fields' => array(
diff --git a/core/modules/views/src/Tests/ViewUnitTestBase.php b/core/modules/views/src/Tests/ViewUnitTestBase.php
index 0d07484..cf66593 100644
--- a/core/modules/views/src/Tests/ViewUnitTestBase.php
+++ b/core/modules/views/src/Tests/ViewUnitTestBase.php
@@ -53,8 +53,6 @@ protected function setUpFixtures() {
       $this->installSchema('views_test_data', $table);
     }
 
-    // The router table is required for router rebuilds.
-    $this->installSchema('system', array('router'));
     \Drupal::service('router.builder')->rebuild();
 
     // Load the test dataset.
