diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc
index 968192e..3e5905a 100644
--- a/core/includes/install.core.inc
+++ b/core/includes/install.core.inc
@@ -171,6 +171,8 @@ function install_state_defaults() {
     'config_verified' => FALSE,
     // TRUE when there is a valid database connection.
     'database_verified' => FALSE,
+    // TRUE if database is empty & ready to install.
+    'database_ready' => FALSE,
     // TRUE when a valid settings.php exists (containing both database
     // connection information and config directory names).
     'settings_verified' => FALSE,
@@ -320,9 +322,6 @@ function install_begin_request(&$install_state) {
   $container
     ->register('string_translation', 'Drupal\Core\StringTranslation\TranslationManager')
     ->addArgument(new Reference('language_manager'));
-  $container
-    ->register('path.matcher', 'Drupal\Core\Path\PathMatcher')
-    ->addArgument(new Reference('config.factory'));
 
   // Register the stream wrapper manager.
   $container
@@ -337,6 +336,13 @@ function install_begin_request(&$install_state) {
   $install_state['database_verified'] = install_verify_database_settings();
   $install_state['settings_verified'] = $install_state['config_verified'] && $install_state['database_verified'];
 
+  // Install factory tables only after checking the database.
+  if ($install_state['database_verified'] && $install_state['database_ready']) {
+    $container
+      ->register('path.matcher', 'Drupal\Core\Path\PathMatcher')
+      ->addArgument(new Reference('config.factory'));
+  }
+
   if ($install_state['settings_verified']) {
     try {
       $system_schema = system_schema();
@@ -684,6 +690,9 @@ function install_tasks($install_state) {
       'run' => $install_state['settings_verified'] ? INSTALL_TASK_SKIP : INSTALL_TASK_RUN_IF_NOT_COMPLETED,
       'function' => 'Drupal\Core\Installer\Form\SiteSettingsForm',
     ),
+    'install_verify_database_ready' => array(
+      'run' => $install_state['database_ready'] ? INSTALL_TASK_SKIP : INSTALL_TASK_RUN_IF_NOT_COMPLETED,
+    ),
     'install_base_system' => array(
       'run' => $install_state['base_system_verified'] ? INSTALL_TASK_SKIP : INSTALL_TASK_RUN_IF_NOT_COMPLETED,
     ),
@@ -1031,6 +1040,21 @@ function install_verify_database_settings() {
 }
 
 /**
+ * Verified that the database is ready (no existing Drupal installation).
+ */
+function install_verify_database_ready() {
+  $system_schema = system_schema();
+  end($system_schema);
+  $table = key($system_schema);
+
+  if ($database = Database::getConnectionInfo()) {
+    if (Database::getConnection()->schema()->tableExists($table)) {
+      throw new AlreadyInstalledException(\Drupal::service('string_translation'));
+    }
+  }
+}
+
+/**
  * Checks a database connection and returns any errors.
  */
 function install_database_errors($database, $settings_file) {
diff --git a/core/modules/system/src/Tests/Installer/InstallerExistingInstallationTest.php b/core/modules/system/src/Tests/Installer/InstallerExistingInstallationTest.php
new file mode 100644
index 0000000..08198db
--- /dev/null
+++ b/core/modules/system/src/Tests/Installer/InstallerExistingInstallationTest.php
@@ -0,0 +1,44 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\system\Tests\Installer\InstallerExistingInstallationTest.
+ */
+
+namespace Drupal\system\Tests\Installer;
+
+use Drupal\simpletest\InstallerTestBase;
+
+/**
+ * Tests the installer with an existing Drupal installation.
+ *
+ * @group Installer
+ */
+class InstallerExistingInstallationTest extends InstallerTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+  }
+
+  /**
+   * Verifies that Drupal can't be reinstalled while an existing installation is
+   * available.
+   */
+  public function testInstaller() {
+    // Verify that Drupal can't be immediately reinstalled.
+    $this->drupalGet($GLOBALS['base_url'] . '/core/install.php');
+    $this->assertRaw('Drupal already installed');
+
+    // Delete settings.php and attempt to reinstall again.
+    unlink($this->siteDirectory . '/settings.php');
+    $this->drupalGet($GLOBALS['base_url'] . '/core/install.php');
+    $this->setUpLanguage();
+    $this->setUpProfile();
+    $this->setUpSettings();
+    $this->assertRaw('Drupal already installed');
+  }
+
+}
