diff --git a/core/lib/Drupal/Core/Menu/LocalTaskManager.php b/core/lib/Drupal/Core/Menu/LocalTaskManager.php
index 171a8d48779eb165e2c2f2c44a0bdee50bc124e4..b70e77fbce5df31bded466dd333bf05e1673c216 100644
--- a/core/lib/Drupal/Core/Menu/LocalTaskManager.php
+++ b/core/lib/Drupal/Core/Menu/LocalTaskManager.php
@@ -360,6 +360,17 @@ public function getLocalTasks($route_name, $level = 0) {
         foreach ($local_tasks as $tab_level => $items) {
           $data[$tab_level] = empty($data[$tab_level]) ? $items : array_merge($data[$tab_level], $items);
         }
+
+        // Sort by weight and alphabetically if weights are the same.
+        foreach ($data as $key => $values) {
+          $weights = array_column($values, '#weight');
+          array_multisort(
+            $weights, SORT_ASC, SORT_NUMERIC,
+            array_keys($values), SORT_ASC, SORT_NATURAL,
+            $data[$key],
+          );
+        }
+
         $this->taskData[$route_name]['tabs'] = $data;
         // Allow modules to alter local tasks.
         $this->moduleHandler->alter('menu_local_tasks', $this->taskData[$route_name], $route_name, $cacheability);
diff --git a/core/tests/Drupal/Tests/Core/Menu/LocalTaskManagerTest.php b/core/tests/Drupal/Tests/Core/Menu/LocalTaskManagerTest.php
index 6a35e40e1da07d0822e6f42537d5a7266e5ada4f..713cfb819c2730a25fd1752ee8be66651fbc5b5c 100644
--- a/core/tests/Drupal/Tests/Core/Menu/LocalTaskManagerTest.php
+++ b/core/tests/Drupal/Tests/Core/Menu/LocalTaskManagerTest.php
@@ -480,4 +480,117 @@ protected function setupNullCacheabilityMetadataValidation(): void {
     \Drupal::setContainer($container);
   }
 
+  /**
+   * Tests the getLocalTasksForRoute method.
+   *
+   * @dataProvider providerTestGetLocalTasks
+   */
+  public function testGetLocalTasks($new_weights, $expected): void {
+    $definitions = $this->getLocalTaskFixtures();
+
+    // Add another child, that will be first in an alphabetical sort.
+    $definitions['menu_local_task_test_tasks_view_a_child'] = [
+      'route_name' => 'menu_local_task_test_tasks_a_child_page',
+      'title' => 'Settings child a_child',
+      'parent_id' => 'menu_local_task_test_tasks_view.tab',
+      'id' => 'menu_local_task_test_tasks_view_a_child',
+      'route_parameters' => [],
+      'base_route' => '',
+      'weight' => 0,
+      'options' => [],
+      'class' => 'Drupal\Core\Menu\LocalTaskDefault',
+    ];
+
+    // Update the task weights.
+    foreach ($new_weights as $local_task => $weight) {
+      $definitions[$local_task] = array_merge($definitions[$local_task], $weight);
+    }
+
+    $this->pluginDiscovery->expects($this->once())
+      ->method('getDefinitions')
+      ->willReturn($definitions);
+
+    $this->setupFactoryAndLocalTaskPlugins($definitions, 'menu_local_task_test_tasks_view');
+    $this->setupLocalTaskManager();
+
+    $this->argumentResolver->expects($this->any())
+      ->method('getArguments')
+      ->willReturn([]);
+
+    $this->routeMatch->expects($this->any())
+      ->method('getRouteName')
+      ->willReturn('menu_local_task_test_tasks_view');
+    $this->routeMatch->expects($this->any())
+      ->method('getRawParameters')
+      ->willReturn(new InputBag());
+
+    $cacheability = new CacheableMetadata();
+    $this->manager->getTasksBuild('menu_local_task_test_tasks_view', $cacheability);
+
+    // Get the local tasks for each level and assert that the order is as
+    // expected.
+    foreach ([0, 1] as $level) {
+      $local_tasks = $this->manager->getLocalTasks('menu_local_task_test_tasks_view', $level);
+      $data = $local_tasks['tabs'];
+      $this->assertEquals($expected[$level], array_keys($data));
+    }
+  }
+
+  /**
+   * Data provider for testGetLocalTasks.
+   */
+  public static function providerTestGetLocalTasks(): array {
+    return [
+      // Weights as setup in getLocalTaskFixtures.
+      'weights_from_fixture' => [
+        'new_weights' => [],
+        'expected' => [
+          // Level 0.
+          [
+            'menu_local_task_test_tasks_settings',
+            'menu_local_task_test_tasks_view.tab',
+            'menu_local_task_test_tasks_edit',
+          ],
+          // Level 1. All weights are 0, so the sort is alphabetical.
+          [
+            'menu_local_task_test_tasks_view_a_child',
+            'menu_local_task_test_tasks_view_child1',
+            'menu_local_task_test_tasks_view_child2',
+          ],
+        ],
+      ],
+      // Change the weights in both levels.
+      'both_levels' => [
+        'new_weights' => [
+          'menu_local_task_test_tasks_view_a_child' => [
+            'weight' => 99,
+          ],
+          'menu_local_task_test_tasks_view_child1' => [
+            'weight' => 100,
+          ],
+          'menu_local_task_test_tasks_view_child2' => [
+            'weight' => -1,
+          ],
+          'menu_local_task_test_tasks_settings' => [
+            'weight' => 100,
+          ],
+        ],
+        'expected' => [
+          // Level 0.
+          [
+            'menu_local_task_test_tasks_view.tab',
+            'menu_local_task_test_tasks_edit',
+            'menu_local_task_test_tasks_settings',
+          ],
+          // Level 1.
+          [
+            'menu_local_task_test_tasks_view_child2',
+            'menu_local_task_test_tasks_view_a_child',
+            'menu_local_task_test_tasks_view_child1',
+          ],
+        ],
+      ],
+    ];
+  }
+
 }