diff --git a/core/includes/update.inc b/core/includes/update.inc
index 792e94c286..d90d3b4afe 100644
--- a/core/includes/update.inc
+++ b/core/includes/update.inc
@@ -404,6 +404,9 @@ function update_resolve_dependencies($starting_updates) {
   // Perform the depth-first search and sort on the results.
   $graph_object = new Graph($graph);
   $graph = $graph_object->searchAndSort();
+  // Prepare the graph for sort.
+  update_prepare_graph_for_sort($graph);
+  // Finally sort the updates by weight.
   uasort($graph, ['Drupal\Component\Utility\SortArray', 'sortByWeightElement']);
 
   foreach ($graph as $function => &$data) {
@@ -433,6 +436,74 @@ function update_resolve_dependencies($starting_updates) {
   return $graph;
 }
 
+/**
+ * Prepares the update graph array for sorting.
+ *
+ * The weights of updates in a group of the same weight containing system
+ * updates will be adjusted, so that we ensure that system updates are executed
+ * as soon as possible.
+ *
+ * For example the following graph:
+ * @code
+ * $graph = [
+ *   'node_update_8xxx' => [
+ *     'weight' => 0,
+ *     'module' => 'node',
+ *   ],
+ *   'system_update_8xxx' => [
+ *     'weight' => 0,
+ *     'module' => 'system',
+ *   ].
+ * ];
+ * @endcode
+ *
+ * will be transformed to:
+ *
+ * @code
+ * $graph = [
+ *   'node_update_8xxx' => [
+ *     'weight' => 1,
+ *     'module' => 'node',
+ *   ],
+ *   'system_update_8xxx' => [
+ *     'weight' => 0,
+ *     'module' => 'system',
+ *   ].
+ * ];
+ * @endcode
+ *
+ * @param array &$graph
+ *   The update graph array.
+ */
+function update_prepare_graph_for_sort(array &$graph) {
+  $weights = [];
+  $system_updates = [];
+  foreach ($graph as $update_name => $update_data) {
+    $weight = $update_data['weight'];
+    $weights[] = $weight;
+    if ($update_data['module'] === 'system') {
+      $system_updates[] = $weight;
+    }
+  }
+  sort($weights);
+  $new_weights  = array_combine($weights, $weights);
+  foreach ($system_updates as $system_update_weight) {
+    foreach ($new_weights as $old_weight => &$new_weight) {
+      if ($old_weight >= $system_update_weight) {
+        $new_weight++;
+      }
+    }
+  }
+  // Increment the weight of all updates in a group with a system update but
+  // leave the system update with the old weight in order for it to be executed
+  // first.
+  foreach ($graph as $update_name => &$update_data) {
+    if ($update_data['module'] !== 'system') {
+      $update_data['weight'] = $new_weights[$update_data['weight']];
+    }
+  }
+}
+
 /**
  * Returns an organized list of update functions for a set of modules.
  *
@@ -549,6 +620,62 @@ function update_build_dependency_graph($update_functions) {
     }
   }
 
+  // A function returning all the updates which directly or indirectly have a
+  // specific update as an edge.
+  $get_all_parents = function($update) use ($graph, &$get_all_parents) {
+    $parents = [];
+    foreach ($graph as $func => $data) {
+      if (isset($data['edges'][$update])) {
+        $parents[] = $func;
+        $parents = array_merge($parents, $get_all_parents($func));
+      }
+    }
+    return array_unique($parents);
+  };
+  // If a given non-system update U1 has an edge pointing to another non-system
+  // update update U2 and U2 has an edge pointing to the a system update S, add
+  // an edge to U1 pointing to S. This ensures that the chain U1->U2->S will be
+  // preserved in that order despite the system updates being moved before any
+  // other updates below.
+  foreach ($graph as $non_system_func => $data) {
+    if ($data['module'] !== 'system') {
+      if (!empty($data['edges'])) {
+        $sys_updates = [];
+        foreach (array_keys($data['edges']) as $edge) {
+          if ($graph[$edge]['module'] === 'system') {
+            $sys_updates[$edge] = TRUE;
+          }
+        }
+        if ($sys_updates) {
+          foreach ($get_all_parents($non_system_func) as $parent_edge) {
+            $graph[$parent_edge]['edges'] = empty($graph[$parent_edge]['edges']) ? $sys_updates : array_unique(array_merge($graph[$parent_edge]['edges'], $sys_updates));
+          }
+        }
+      }
+    }
+  }
+  // Find update functions without edges to system updates and add such updates
+  // as edges to system updates so that system updates are executed first.
+  foreach ($graph as $system_function => &$system_data) {
+    if ($system_data['module'] === 'system') {
+      foreach ($graph as $non_system_function => $non_system_data) {
+        if ($non_system_data['module'] !== 'system') {
+          $contains_system_update_edge = FALSE;
+          $edges = empty($non_system_data['edges']) ? [] : array_keys($non_system_data['edges']);
+          foreach ($edges as $edge) {
+            if ($graph[$edge]['module'] === 'system') {
+              $contains_system_update_edge = TRUE;
+              break;
+            }
+          }
+          if (!$contains_system_update_edge) {
+            $system_data['edges'][$non_system_function] = TRUE;
+          }
+        }
+      }
+    }
+  }
+
   return $graph;
 }
 
diff --git a/core/tests/Drupal/FunctionalTests/Update/UpdatePathTestBase.php b/core/tests/Drupal/FunctionalTests/Update/UpdatePathTestBase.php
index d7bad28513..fe1eb1ef68 100644
--- a/core/tests/Drupal/FunctionalTests/Update/UpdatePathTestBase.php
+++ b/core/tests/Drupal/FunctionalTests/Update/UpdatePathTestBase.php
@@ -5,6 +5,7 @@
 use Drupal\Component\Utility\Crypt;
 use Drupal\Core\Site\Settings;
 use Drupal\Core\Test\TestRunnerKernel;
+use Drupal\system\Controller\DbUpdateController;
 use Drupal\Tests\BrowserTestBase;
 use Drupal\Tests\SchemaCheckTestTrait;
 use Drupal\Core\Database\Database;
@@ -207,6 +208,8 @@ protected function setUp() {
 
     // Set up the browser test output file.
     $this->initBrowserOutputFile();
+
+    $this->assertSystemUpdatesPriorityExecution();
   }
 
   /**
@@ -325,6 +328,14 @@ protected function runUpdates() {
         $this->fail('The update failed with the following message: "' . reset($failure)->getText() . '"');
       }
 
+      // The update test might be retrieving the schema version of a module
+      // before the updates are executed, which will now lead to
+      // update_get_update_list() retrieving the schema version prior to the
+      // update. To prevent this we reset the static cache of
+      // drupal_get_installed_schema_version() so that more complex update path
+      // testing works.
+      drupal_static_reset('drupal_get_installed_schema_version');
+
       // Ensure that there are no pending updates.
       foreach (['update', 'post_update'] as $update_type) {
         switch ($update_type) {
@@ -458,4 +469,46 @@ protected function doSelectionTest() {
     // and implement their required tests.
   }
 
+  /**
+   * Asserts that system updates will be executed first.
+   */
+  protected function assertSystemUpdatesPriorityExecution() {
+    // Ensure install files are loaded. We reset the static cache as if the
+    // update functions for retrieving update information have been called they
+    // might contain an old data.
+    // @see drupal_get_schema_versions().
+    drupal_static_reset('drupal_get_installed_schema_version');
+    drupal_static_reset('drupal_get_schema_versions');
+
+    foreach ($this->container->get('module_handler')->getModuleList() as $loaded_module => $filename) {
+      module_load_install($loaded_module);
+    }
+
+    $db_update_controller = DbUpdateController::create($this->container);
+    $get_module_updates = function () {
+      return $this->getModuleUpdates();
+    };
+    $get_module_updates = $get_module_updates->bindTo($db_update_controller, $db_update_controller);
+    $starting_updates = $get_module_updates();
+    $updates = update_resolve_dependencies($starting_updates);
+
+    if ($updates) {
+      $first_update = reset($updates);
+      $system_updates_finished = !$first_update['module'] === 'system';
+      foreach ($updates as $function => $update) {
+        if ($update['module'] === 'system') {
+          $this->assertFalse($system_updates_finished, "System update {$function} should be among the first updates.");
+        }
+        else {
+          $system_updates_finished = TRUE;
+        }
+      }
+    }
+
+    // Reset the static cache once more as ::runUpdates() is relying on it being
+    // populated after the updates have been executed and not before that.
+    drupal_static_reset('drupal_get_installed_schema_version');
+    drupal_static_reset('drupal_get_schema_versions');
+  }
+
 }
