diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index 91ca349..de2bac4 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -2197,10 +2197,6 @@ function _drupal_exception_handler($exception) {
  * Sets up the script environment and loads settings.php.
  */
 function _drupal_bootstrap_configuration() {
-  // Set the Drupal custom error handler.
-  set_error_handler('_drupal_error_handler');
-  set_exception_handler('_drupal_exception_handler');
-
   drupal_environment_initialize();
   // Start a page timer:
   timer_start('page');
@@ -2215,6 +2211,11 @@ function _drupal_bootstrap_configuration() {
 
   // Load the procedural configuration system helper functions.
   require_once DRUPAL_ROOT . '/core/includes/config.inc';
+
+  // Set the Drupal custom error handler. (requires config())
+  set_error_handler('_drupal_error_handler');
+  set_exception_handler('_drupal_exception_handler');
+
   // Redirect the user to the installation script if Drupal has not been
   // installed yet (i.e., if no $databases array has been defined in the
   // settings.php file) and we are not already installing.
diff --git a/core/includes/errors.inc b/core/includes/errors.inc
index 5fc4b7d..e42b284 100644
--- a/core/includes/errors.inc
+++ b/core/includes/errors.inc
@@ -153,8 +153,13 @@ function _drupal_render_exception_safe($exception) {
  *   TRUE if an error should be displayed.
  */
 function error_displayable($error = NULL) {
-  $error_level = config('system.logging')->get('error_level');
   $updating = (defined('MAINTENANCE_MODE') && MAINTENANCE_MODE == 'update');
+  if ($updating) {
+    $error_level = ERROR_REPORTING_DISPLAY_VERBOSE;
+  }
+  else {
+    $error_level = config('system.logging')->get('error_level');
+  }
   $all_errors_displayed = ($error_level == ERROR_REPORTING_DISPLAY_ALL) ||
     ($error_level == ERROR_REPORTING_DISPLAY_VERBOSE);
   $error_needs_display = ($error_level == ERROR_REPORTING_DISPLAY_SOME &&
diff --git a/core/includes/update.inc b/core/includes/update.inc
index 299a81c..791fb54 100644
--- a/core/includes/update.inc
+++ b/core/includes/update.inc
@@ -88,11 +88,6 @@ function update_check_incompatibility($name, $type = 'module') {
  * irreversible changes to the database are made here.
  */
 function update_prepare_d8_bootstrap() {
-  include_once DRUPAL_ROOT . '/core/includes/install.inc';
-  include_once DRUPAL_ROOT . '/core/includes/schema.inc';
-  // Bootstrap to configuration.
-  drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION);
-
   // Check whether settings.php needs to be rewritten.
   $settings_exist = !empty($GLOBALS['config_directories']);
 
@@ -142,12 +137,7 @@ function update_prepare_d8_bootstrap() {
   // running an up-to-date version of Drupal 7 before proceeding. Note this has
   // to happen AFTER the database bootstraps because of
   // drupal_get_installed_schema_version().
-  try {
-    $system_schema = drupal_get_installed_schema_version('system');
-  }
-  catch (\Exception $e) {
-    $system_schema = db_query('SELECT schema_version FROM {system} WHERE name = :system', array(':system' => 'system'))->fetchField();
-  }
+  $system_schema = update_get_schema_version('system');
   if ($system_schema < 8000) {
     $has_required_schema = $system_schema >= REQUIRED_D7_SCHEMA_VERSION;
     $requirements = array(
@@ -159,146 +149,154 @@ function update_prepare_d8_bootstrap() {
       ),
     );
     update_extra_requirements($requirements);
+  }
 
-    // @todo update.php stages seem to be completely screwed up; the initial
-    //   requirements check is not supposed to change the system. All of the
-    //   following code seems to have been mistakenly/unknowingly added here and
-    //   does not belong into update_prepare_d8_bootstrap().
-    if ($has_required_schema) {
-      if (!db_table_exists('key_value')) {
-        $specs = array(
-          'description' => 'Generic key-value storage table. See state() for an example.',
-          'fields' => array(
-            'collection' => array(
-              'description' => 'A named collection of key and value pairs.',
-              'type' => 'varchar',
-              'length' => 128,
-              'not null' => TRUE,
-              'default' => '',
-            ),
-            'name' => array(
-              'description' => 'The key of the key-value pair. As KEY is a SQL reserved keyword, name was chosen instead.',
-              'type' => 'varchar',
-              'length' => 128,
-              'not null' => TRUE,
-              'default' => '',
-            ),
-            'value' => array(
-              'description' => 'The value.',
-              'type' => 'blob',
-              'not null' => TRUE,
-              'size' => 'big',
-              'translatable' => TRUE,
-            ),
-          ),
-          'primary key' => array('collection', 'name'),
-        );
-        db_create_table('key_value', $specs);
-      }
-      // Bootstrap variables so we can update theme while preparing the update
-      // process.
-      drupal_bootstrap(DRUPAL_BOOTSTRAP_VARIABLES);
-
-      // Update the 'language_default' system variable, if configured.
-      // Required to run before drupal_install_config_directories(), since that
-      // triggers a call into system_stream_wrappers(), which calls t(), which
-      // calls into language_default().
-      $language_default = variable_get('language_default');
-      if (!empty($language_default) && (isset($language_default->langcode) || isset($language_default->language))) {
-        if (!isset($language_default->langcode)) {
-          $language_default->langcode = $language_default->language;
-        }
-        unset($language_default->language);
-        // In D8, the 'language_default' is not anymore an object, but an array,
-        // so make sure that the new value that is saved into this variable is an
-        // array.
-        variable_set('language_default', (array) $language_default);
-      }
+  // @todo update.php stages seem to be completely screwed up; the initial
+  //   requirements check is not supposed to change the system. All of the
+  //   following code seems to have been mistakenly/unknowingly added here and
+  //   does not belong into update_prepare_d8_bootstrap().
+
+  // Create key_value table.
+  if (!db_table_exists('key_value')) {
+    $specs = array(
+      'description' => 'Generic key-value storage table. See state() for an example.',
+      'fields' => array(
+        'collection' => array(
+          'description' => 'A named collection of key and value pairs.',
+          'type' => 'varchar',
+          'length' => 128,
+          'not null' => TRUE,
+          'default' => '',
+        ),
+        'name' => array(
+          'description' => 'The key of the key-value pair. As KEY is a SQL reserved keyword, name was chosen instead.',
+          'type' => 'varchar',
+          'length' => 128,
+          'not null' => TRUE,
+          'default' => '',
+        ),
+        'value' => array(
+          'description' => 'The value.',
+          'type' => 'blob',
+          'not null' => TRUE,
+          'size' => 'big',
+          'translatable' => TRUE,
+        ),
+      ),
+      'primary key' => array('collection', 'name'),
+    );
+    db_create_table('key_value', $specs);
+  }
+  // Bootstrap variables so we can update theme while preparing the update
+  // process.
+  drupal_bootstrap(DRUPAL_BOOTSTRAP_VARIABLES);
+
+  // Update the 'language_default' system variable, if configured.
+  // Required to run before drupal_install_config_directories(), since that
+  // triggers a call into system_stream_wrappers(), which calls t(), which
+  // calls into language_default().
+  $language_default = variable_get('language_default');
+  if (!empty($language_default) && (isset($language_default->langcode) || isset($language_default->language))) {
+    if (!isset($language_default->langcode)) {
+      $language_default->langcode = $language_default->language;
+    }
+    unset($language_default->language);
+    // In D8, the 'language_default' is not anymore an object, but an array,
+    // so make sure that the new value that is saved into this variable is an
+    // array.
+    variable_set('language_default', (array) $language_default);
+  }
 
-      $module_config = config('system.module');
-      $disabled_modules = config('system.module.disabled');
-      $theme_config = config('system.theme');
-      $disabled_themes = config('system.theme.disabled');
-      $schema_store = drupal_container()->get('keyvalue')->get('system.schema');
-
-      // Load system.module, because update_prepare_d8_bootstrap() is called in
-      // the initial minimal update.php bootstrap that performs the core
-      // requirements check.
-      require_once DRUPAL_ROOT . '/core/modules/system/system.module';
-
-      // Make sure that the bootstrap cache is cleared as that might contain
-      // incompatible data structures.
-      cache('bootstrap')->deleteAll();
-
-      // Retrieve all installed extensions from the {system} table.
-      // Uninstalled extensions are ignored and not converted.
-      $result = db_query('SELECT name, status, weight, schema_version, type FROM {system} WHERE type = :theme OR (type = :module AND schema_version <> :schema_uninstalled)', array(
-        ':theme' => 'theme',
-        ':module' => 'module',
-        ':schema_uninstalled' => SCHEMA_UNINSTALLED,
-      ));
-
-      // Populate a fixed module list (again, why did it get lost?) to avoid
-      // errors due to the drupal_alter() in _system_rebuild_module_data().
-      $module_list['system']['filename'] = 'core/modules/system/system.module';
-      module_list(NULL, $module_list);
-      $module_data = _system_rebuild_module_data();
-
-      // Migrate each extension into configuration, varying by the extension's
-      // status, and record its schema version.
-      foreach ($result as $record) {
-        if ($record->type == 'module') {
-          if ($record->status && isset($module_data[$record->name])) {
-            $module_config->set('enabled.' . $record->name, $record->weight);
-          }
-          else {
-            $disabled_modules->set($record->name, $record->weight);
-          }
+  // Migrate {system} table into config.
+  if (db_table_exists('system')) {
+    $module_config = config('system.module');
+    $disabled_modules = config('system.module.disabled');
+    $theme_config = config('system.theme');
+    $disabled_themes = config('system.theme.disabled');
+    $schema_store = drupal_container()->get('keyvalue')->get('system.schema');
+
+    // Load system.module, because update_prepare_d8_bootstrap() is called in
+    // the initial minimal update.php bootstrap that performs the core
+    // requirements check.
+    require_once DRUPAL_ROOT . '/core/modules/system/system.module';
+
+    // Make sure that the bootstrap cache is cleared as that might contain
+    // incompatible data structures.
+    cache('bootstrap')->deleteAll();
+
+    // Retrieve all installed extensions from the {system} table.
+    // Uninstalled extensions are ignored and not converted.
+    $result = db_query('SELECT name, status, weight, schema_version, type FROM {system} WHERE type = :theme OR (type = :module AND schema_version <> :schema_uninstalled)', array(
+      ':theme' => 'theme',
+      ':module' => 'module',
+      ':schema_uninstalled' => SCHEMA_UNINSTALLED,
+    ));
+
+    // Populate a fixed module list (again, why did it get lost?) to avoid
+    // errors due to the drupal_alter() in _system_rebuild_module_data().
+    $module_list['system']['filename'] = 'core/modules/system/system.module';
+    module_list(NULL, $module_list);
+    $module_data = _system_rebuild_module_data();
+
+    // Migrate each extension into configuration, varying by the extension's
+    // status, and record its schema version.
+    foreach ($result as $record) {
+      if ($record->type == 'module') {
+        if ($record->status && isset($module_data[$record->name])) {
+          $module_config->set('enabled.' . $record->name, $record->weight);
         }
-        elseif ($record->type == 'theme') {
-          if ($record->status) {
-            $theme_config->set('enabled.' . $record->name, 0);
-          }
-          else {
-            $disabled_themes->set($record->name, 0);
-          }
+        else {
+          $disabled_modules->set($record->name, $record->weight);
         }
-        $schema_store->set($record->name, $record->schema_version);
       }
-      $module_config->set('enabled', module_config_sort($module_config->get('enabled')))->save();
-      $disabled_modules->save();
-      $theme_config->save();
-      $disabled_themes->save();
-
-      // Update the dynamic include paths that might be used before running the
-      // proper update functions.
-      update_prepare_stored_includes();
-      // Update the environment for the language bootstrap if needed.
-      update_prepare_d8_language();
-      // Prime the classloader.
-      system_list('module_enabled');
-
-      // Change language column to langcode in url_alias.
-      if (db_table_exists('url_alias') && db_field_exists('url_alias', 'language')) {
-        db_drop_index('url_alias', 'alias_language_pid');
-        db_drop_index('url_alias', 'source_language_pid');
-        $langcode_spec = array(
-          'description' => "The language code this alias is for; if 'und', the alias will be used for unknown languages. Each Drupal path can have an alias for each supported language.",
-          'type' => 'varchar',
-          'length' => 12,
-          'not null' => TRUE,
-          'default' => '',
-        );
-        $langcode_indexes = array('indexes' =>
-          array(
-            'alias_langcode_pid' => array('alias', 'langcode', 'pid'),
-            'source_langcode_pid' => array('source', 'langcode', 'pid'),
-          ),
-        );
-        db_change_field('url_alias', 'language', 'langcode', $langcode_spec, $langcode_indexes);
+      elseif ($record->type == 'theme') {
+        if ($record->status) {
+          $theme_config->set('enabled.' . $record->name, 0);
+        }
+        else {
+          $disabled_themes->set($record->name, 0);
+        }
       }
+      $schema_store->set($record->name, $record->schema_version);
     }
+    $module_config->set('enabled', module_config_sort($module_config->get('enabled')))->save();
+    $disabled_modules->save();
+    $theme_config->save();
+    $disabled_themes->save();
+  }
+
+  // Update the dynamic include paths that might be used before running the
+  // proper update functions.
+  update_prepare_stored_includes();
+  // Update the environment for the language bootstrap if needed.
+  update_prepare_d8_language();
+  // Prime the classloader.
+  system_list('module_enabled');
+
+  // Change language column to langcode in url_alias.
+  if (db_table_exists('url_alias') && db_field_exists('url_alias', 'language')) {
+    db_drop_index('url_alias', 'alias_language_pid');
+    db_drop_index('url_alias', 'source_language_pid');
+    $langcode_spec = array(
+      'description' => "The language code this alias is for; if 'und', the alias will be used for unknown languages. Each Drupal path can have an alias for each supported language.",
+      'type' => 'varchar',
+      'length' => 12,
+      'not null' => TRUE,
+      'default' => '',
+    );
+    $langcode_indexes = array('indexes' =>
+      array(
+        'alias_langcode_pid' => array('alias', 'langcode', 'pid'),
+        'source_langcode_pid' => array('source', 'langcode', 'pid'),
+      ),
+    );
+    db_change_field('url_alias', 'language', 'langcode', $langcode_spec, $langcode_indexes);
   }
+
+  // Remove the module list overrides from above.
+  // @todo Lock update.php to an empty module list.
+  // @see http://drupal.org/node/922996
+  module_list_reset();
 }
 
 /**
@@ -321,6 +319,7 @@ function update_prepare_stored_includes() {
  * Prepare Drupal 8 language changes for the bootstrap if needed.
  */
 function update_prepare_d8_language() {
+  // {languages} is renamed to {language} below.
   if (db_table_exists('languages')) {
     $languages = db_select('languages', 'l')
       ->fields('l')
@@ -496,16 +495,35 @@ function update_prepare_d8_language() {
  * made which make it impossible to continue using the prior version.
  */
 function update_fix_d8_requirements() {
-  global $conf;
-
-  if (drupal_get_installed_schema_version('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.
+  // File module provides the storage and API for managed files in D8,
+  // previously provided by System module. Its database schema already exists,
+  // but the upgrade path needs to include all File module updates. Since module
+  // updates are collected only once before they are executed, it has to be
+  // enabled before available updates are collected.
+  // This change happened when System module's schema version was 8018. File
+  // module must not be enabled for existing D8 sites that do not need it.
+  if (update_get_schema_version('file') == SCHEMA_UNINSTALLED && update_get_schema_version('system') <= 8018) {
     update_module_enable(array('file'));
+  }
+}
 
-    update_variable_set('update_d8_requirements', TRUE);
+/**
+ * Returns the installed schema version of an extension.
+ *
+ * @param string $name
+ *   The name of an extension; e.g., 'system'.
+ *
+ * @return int
+ *   The installed schema version.
+ */
+function update_get_schema_version($name) {
+  try {
+    $version = drupal_get_installed_schema_version($name);
+  }
+  catch (\Exception $e) {
+    $version = db_query('SELECT schema_version FROM {system} WHERE name = :name', array(':name' => $name))->fetchField();
   }
+  return $version;
 }
 
 /**
diff --git a/core/lib/Drupal/Core/DrupalKernel.php b/core/lib/Drupal/Core/DrupalKernel.php
index b011271..0c74851 100644
--- a/core/lib/Drupal/Core/DrupalKernel.php
+++ b/core/lib/Drupal/Core/DrupalKernel.php
@@ -303,7 +303,7 @@ protected function initializeContainer() {
 
       // If 'container.modules' is wrong, the container must be rebuilt.
       if (!isset($this->moduleList)) {
-        $this->moduleList = $this->container->get('config.factory')->get('system.module')->load()->get('enabled');
+        $this->moduleList = $this->container->get('config.factory')->get('system.module')->load()->get('enabled') ?: array();
       }
       if (array_keys($this->moduleList) !== array_keys($container_modules)) {
         unset($this->container);
diff --git a/core/update.php b/core/update.php
index ff65c6e..605f9a5 100644
--- a/core/update.php
+++ b/core/update.php
@@ -394,10 +394,6 @@ function update_check_requirements($skip_warnings = FALSE) {
   }
 }
 
-// Some unavoidable errors happen because the database is not yet up-to-date.
-// Our custom error handler is not yet installed, so we just suppress them.
-ini_set('display_errors', FALSE);
-
 // We prepare a minimal bootstrap for the update requirements check to avoid
 // reaching the PHP memory limit.
 require_once DRUPAL_ROOT . '/core/includes/bootstrap.inc';
@@ -406,6 +402,10 @@ function update_check_requirements($skip_warnings = FALSE) {
 require_once DRUPAL_ROOT . '/core/includes/file.inc';
 require_once DRUPAL_ROOT . '/core/includes/unicode.inc';
 require_once DRUPAL_ROOT . '/core/includes/schema.inc';
+include_once DRUPAL_ROOT . '/core/includes/install.inc';
+include_once DRUPAL_ROOT . '/core/includes/database.inc';
+include_once DRUPAL_ROOT . '/core/includes/cache.inc';
+drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION);
 update_prepare_d8_bootstrap();
 
 // Determine if the current user has access to run update.php.
