diff --git a/core/lib/Drupal/Core/Menu/MenuLinkTree.php b/core/lib/Drupal/Core/Menu/MenuLinkTree.php
index ddf924c..25dede7 100644
--- a/core/lib/Drupal/Core/Menu/MenuLinkTree.php
+++ b/core/lib/Drupal/Core/Menu/MenuLinkTree.php
@@ -107,7 +107,7 @@ public function getCurrentRouteMenuTreeParameters($menu_name) {
     ksort($route_parameters);
     $cid = 'current-route-parameters:' . $menu_name . ':route:' . $this->routeMatch->getRouteName() . ':route_parameters:' . serialize($route_parameters);
 
-    if (!isset($this->cachedCurrentRouteParameters[$menu_name])) {
+    if (!isset($this->cachedCurrentRouteParameters[$cid])) {
       $cache = $this->cache->get($cid);
       if ($cache && $cache->data) {
         $parameters = $cache->data;
diff --git a/core/modules/system/config/schema/system.schema.yml b/core/modules/system/config/schema/system.schema.yml
index 2e9219d..3809d51 100644
--- a/core/modules/system/config/schema/system.schema.yml
+++ b/core/modules/system/config/schema/system.schema.yml
@@ -375,6 +375,17 @@ block.settings.system_branding_block:
       type: boolean
       label: 'Use site slogan'
 
+block.settings.system_menu_block:*:
+  type: block_settings
+  label: 'Menu block'
+  mapping:
+    level:
+      type: integer
+      label: 'Starting level'
+    depth:
+      type: integer
+      label: 'Maximum number of levels'
+
 condition.plugin.request_path:
   type: condition.plugin
   mapping:
diff --git a/core/modules/system/src/Plugin/Block/SystemMenuBlock.php b/core/modules/system/src/Plugin/Block/SystemMenuBlock.php
index dd4c6ad..67fc4b0 100644
--- a/core/modules/system/src/Plugin/Block/SystemMenuBlock.php
+++ b/core/modules/system/src/Plugin/Block/SystemMenuBlock.php
@@ -9,12 +9,13 @@
 
 use Drupal\Component\Utility\NestedArray;
 use Drupal\Core\Block\BlockBase;
-use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\Core\Cache\Cache;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Menu\MenuActiveTrailInterface;
 use Drupal\Core\Menu\MenuLinkTreeInterface;
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
-
 /**
  * Provides a generic Menu block.
  *
@@ -77,9 +78,67 @@ public static function create(ContainerInterface $container, array $configuratio
   /**
    * {@inheritdoc}
    */
+  public function blockForm($form, FormStateInterface $form_state) {
+    $config = $this->configuration;
+
+    $options = array(
+      1 => $this->t('1st level (primary)'),
+      2 => $this->t('2nd level (secondary)'),
+      3 => $this->t('3rd level (tertiary)'),
+      4 => $this->t('4th level'),
+      5 => $this->t('5th level'),
+      6 => $this->t('6th level'),
+      7 => $this->t('7th level'),
+      8 => $this->t('8th level'),
+      9 => $this->t('9th level'),
+      10 => $this->t('10th level'),
+      11 => $this->t('11th level'),
+      12 => $this->t('12th level'),
+    );
+    // Remove the options that are unsupported by the current menu tree storage
+    // back-end.
+    $level_count = count($options);
+    for ($i = $this->menuTree->maxDepth() + 1; $i <= $level_count; $i++) {
+      unset($options[$i]);
+    }
+
+    $form['level'] = array(
+      '#type' => 'select',
+      '#title' => $this->t('Starting level'),
+      '#default_value' => $config['level'],
+      '#options' => $options,
+      '#description' => $this->t('Blocks that start with the 1st level will always be visible. Blocks that start with the 2nd level or deeper will only be visible when the trail to the active menu passes through the block’s starting level.'),
+      '#required' => TRUE,
+    );
+
+    $options = range(0, $this->menuTree->maxDepth());
+    $options[0] = $this->t('Unlimited');
+
+    $form['depth'] = array(
+      '#type' => 'select',
+      '#title' => $this->t('Maximum number of levels'),
+      '#default_value' => $config['depth'],
+      '#options' => $options,
+      '#description' => $this->t('Specify the maximum number of levels of the menu tree to display, beginning with the starting level.'),
+      '#required' => TRUE,
+    );
+
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function build() {
     $menu_name = $this->getDerivativeId();
     $parameters = $this->menuTree->getCurrentRouteMenuTreeParameters($menu_name);
+
+    // Adjust the menu tree parameters based on the block's configuration.
+    $level = $this->configuration['level'];
+    $depth = $this->configuration['depth'];
+    $parameters->setMinDepth($level);
+    $parameters->setMaxDepth(($depth === 0) ? NULL : min($level + $depth - 1, $this->menuTree->maxDepth()));
+
     $tree = $this->menuTree->load($menu_name, $parameters);
     $manipulators = array(
       array('callable' => 'menu.default_tree_manipulators:checkAccess'),
@@ -101,7 +160,11 @@ public function defaultConfiguration() {
     // 1) it is possible to set a different max age for individual blocks, since
     //    this is just the default value.
     // 2) modules can modify caching by implementing hook_block_view_alter()
-    return array('cache' => array('max_age' => \Drupal\Core\Cache\Cache::PERMANENT));
+    return array(
+      'cache' => array('max_age' => Cache::PERMANENT),
+      'level' => 1,
+      'depth' => 0,
+    );
   }
 
   /**
diff --git a/core/modules/system/src/Tests/Block/SystemMenuBlockTest.php b/core/modules/system/src/Tests/Block/SystemMenuBlockTest.php
index 80c3d3d..c7f20da 100644
--- a/core/modules/system/src/Tests/Block/SystemMenuBlockTest.php
+++ b/core/modules/system/src/Tests/Block/SystemMenuBlockTest.php
@@ -5,7 +5,14 @@
 
 namespace Drupal\system\Tests\Block;
 
-use Drupal\simpletest\DrupalUnitTestBase;
+use Drupal\Core\Render\Element;
+use Drupal\simpletest\KernelTestBase;
+use Drupal\system\Tests\Routing\MockRouteProvider;
+use Drupal\Tests\Core\Menu\MenuLinkMock;
+use Symfony\Cmf\Component\Routing\RouteObjectInterface;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\Routing\Route;
+use Symfony\Component\Routing\RouteCollection;
 
 /**
  * Tests \Drupal\system\Plugin\Block\SystemMenuBlock.
@@ -17,32 +24,126 @@
  * @see \Drupal\system\Plugin\Derivative\SystemMenuBlock
  * @see \Drupal\system\Plugin\Block\SystemMenuBlock
  */
-class SystemMenuBlockTest extends DrupalUnitTestBase {
+class SystemMenuBlockTest extends KernelTestBase {
 
   /**
    * Modules to enable.
    *
    * @var array
    */
-  public static $modules = array('system', 'block');
+  public static $modules = array(
+    'system',
+    'block',
+    'menu_test',
+    'menu_link_content',
+    'field',
+  );
 
   /**
-   * Tests calculation of a system menu block's configuration dependencies.
+   * The block under test.
+   *
+   * @var \Drupal\system\Plugin\Block\SystemMenuBlock
    */
-  public function testSystemMenuBlockConfigDependencies() {
+  protected $block;
+
+  /**
+   * The menu for testing.
+   *
+   * @var \Drupal\system\MenuInterface
+   */
+  protected $menu;
+
+  /**
+   * The menu link tree service.
+   *
+   * @var \Drupal\Core\Menu\MenuLinkTree
+   */
+  protected $linkTree;
+
+  /**
+   * The menu link plugin manager service.
+   *
+   * @var \Drupal\Core\Menu\MenuLinkManagerInterface $menuLinkManager
+   */
+  protected $menuLinkManager;
+
+  /**
+   * The block manager service.
+   *
+   * @var \Drupal\Core\block\BlockManagerInterface
+   */
+  protected $blockManager;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+    $this->installSchema('system', array('router'));
+    $this->installEntitySchema('menu_link_content');
+
+    $this->menuLinkManager = $this->container->get('plugin.manager.menu.link');
+    $this->linkTree = $this->container->get('menu.link_tree');
+    $this->blockManager = $this->container->get('plugin.manager.block');
+
+    $routes = new RouteCollection();
+    $requirements = array('_access' => 'TRUE');
+    $options = array('_access_checks' => array('access_check.default'));
+    $routes->add('example1', new Route('/example1', array(), $requirements, $options));
+    $routes->add('example2', new Route('/example2', array(), $requirements, $options));
+    $routes->add('example3', new Route('/example3', array(), $requirements, $options));
+    $routes->add('example4', new Route('/example4', array(), $requirements, $options));
+    $routes->add('example5', new Route('/example5', array(), $requirements, $options));
+    $routes->add('example6', new Route('/example6', array(), $requirements, $options));
+    $routes->add('example7', new Route('/example7', array(), $requirements, $options));
+    $routes->add('example8', new Route('/example8', array(), $requirements, $options));
+
+    $mock_route_provider = new MockRouteProvider($routes);
+    $this->container->set('router.route_provider', $mock_route_provider);
+
     // Add a new custom menu.
-    $menu_name = $this->randomMachineName(16);
+    $menu_name = 'mock';
     $label = $this->randomMachineName(16);
 
-    $menu = entity_create('menu', array(
+    $this->menu = entity_create('menu', array(
       'id' => $menu_name,
       'label' => $label,
       'description' => 'Description text',
     ));
-    $menu->save();
+    $this->menu->save();
+
+    // This creates a tree with the following structure:
+    // - 1
+    // - 2
+    //   - 3
+    //     - 4
+    // - 5
+    //   - 7
+    // - 6
+    // - 8
+    // With link 6 being the only external link.
+    $links = array(
+      1 => MenuLinkMock::create(array('id' => 'test.example1', 'route_name' => 'example1', 'title' => 'foo', 'parent' => '', 'weight' => 0)),
+      2 => MenuLinkMock::create(array('id' => 'test.example2', 'route_name' => 'example2', 'title' => 'bar', 'parent' => '', 'route_parameters' => array('foo' => 'bar'), 'weight' => 1)),
+      3 => MenuLinkMock::create(array('id' => 'test.example3', 'route_name' => 'example3', 'title' => 'baz', 'parent' => 'test.example2', 'weight' => 2)),
+      4 => MenuLinkMock::create(array('id' => 'test.example4', 'route_name' => 'example4', 'title' => 'qux', 'parent' => 'test.example3', 'weight' => 3)),
+      5 => MenuLinkMock::create(array('id' => 'test.example5', 'route_name' => 'example5', 'title' => 'foofoo', 'parent' => '', 'expanded' => TRUE, 'weight' => 4)),
+      6 => MenuLinkMock::create(array('id' => 'test.example6', 'route_name' => '', 'url' => 'https://drupal.org/', 'title' => 'barbar', 'parent' => '', 'weight' => 5)),
+      7 => MenuLinkMock::create(array('id' => 'test.example7', 'route_name' => 'example7', 'title' => 'bazbaz', 'parent' => 'test.example5', 'weight' => 6)),
+      8 => MenuLinkMock::create(array('id' => 'test.example8', 'route_name' => 'example8', 'title' => 'quxqux', 'parent' => '', 'weight' => 7)),
+    );
+    foreach ($links as $instance) {
+      $this->menuLinkManager->addDefinition($instance->getPluginId(), $instance->getPluginDefinition());
+    }
+  }
+
+  /**
+   * Tests calculation of a system menu block's configuration dependencies.
+   */
+  public function testSystemMenuBlockConfigDependencies() {
 
     $block = entity_create('block', array(
-      'plugin' => 'system_menu_block:'. $menu->id(),
+      'plugin' => 'system_menu_block:' . $this->menu->id(),
       'region' => 'footer',
       'id' => 'machinename',
       'theme' => 'stark',
@@ -50,16 +151,134 @@ public function testSystemMenuBlockConfigDependencies() {
 
     $dependencies = $block->calculateDependencies();
     $expected = array(
-      'entity' => array(
-        'system.menu.' . $menu->id()
-      ),
-      'module' => array(
-        'system'
-      ),
-      'theme' => array(
-        'stark'
-      ),
+      'entity' => array('system.menu.' . $this->menu->id()),
+      'module' => array('system'),
+      'theme' => array('stark'),
     );
     $this->assertIdentical($expected, $dependencies);
   }
+
+  /**
+   * Tests the config start level and depth.
+   */
+  public function testConfigLevelDepth() {
+    // Helper function to "ASCIIfy" a tree returned by MenuLinkTree::build().
+    $asciify = function(array $build, $indentation = 0) use (&$asciify) {
+      $prefix = '';
+      if ($indentation > 0) {
+        $prefix = str_repeat('  ', $indentation) . '|- ';
+      }
+
+      $output = '';
+      foreach (Element::children($build) as $id) {
+        $output .= $prefix . $id . "\n";
+        if (isset($build[$id]['#below'])) {
+          $output .= $asciify($build[$id]['#below'], $indentation + 1);
+        }
+      }
+      return $output;
+    };
+
+    // Helper function to generate a configured block instance.
+    $place_block = function ($level, $depth) {
+      return $this->blockManager->createInstance('system_menu_block:' . $this->menu->id(), array(
+        'region' => 'footer',
+        'id' => 'machinename',
+        'theme' => 'stark',
+        'level' => $level,
+        'depth' => $depth,
+      ));
+    };
+
+    // All the different block instances we're going to test.
+    $blocks = [
+      'all' => $place_block(1, 0),
+      'level_1_only' => $place_block(1, 1),
+      'level_2_only' => $place_block(2, 1),
+      'level_3_only' => $place_block(3, 1),
+      'level_1_and_beyond' => $place_block(1, 0),
+      'level_2_and_beyond' => $place_block(2, 0),
+      'level_3_and_beyond' => $place_block(3, 0),
+    ];
+
+    // Scenario 1: test all block instances when there's no active trail.
+    $no_active_trail_expectations = [];
+    $no_active_trail_expectations['all'] = <<<EOF
+test.example1
+test.example2
+test.example5
+  |- test.example7
+test.example6
+test.example8
+
+EOF;
+    $no_active_trail_expectations['level_1_only'] = <<<EOF
+test.example1
+test.example2
+test.example5
+test.example6
+test.example8
+
+EOF;
+    $no_active_trail_expectations['level_2_only'] = <<<EOF
+test.example7
+
+EOF;
+    $no_active_trail_expectations['level_3_only'] = '';
+    $no_active_trail_expectations['level_1_and_beyond'] = $no_active_trail_expectations['all'];
+    $no_active_trail_expectations['level_2_and_beyond'] = $no_active_trail_expectations['level_2_only'];
+    $no_active_trail_expectations['level_3_and_beyond'] = '';
+    foreach ($blocks as $id => $block) {
+      $this->assertIdentical($no_active_trail_expectations[$id], $asciify($block->build()), format_string('Menu block %id with no active trail renders the expected tree.', ['%id' => $id]));
+    }
+
+    // Scenario 1: test all block instances when there's an active trail.
+    $route = $this->container->get('router.route_provider')->getRouteByName('example3');
+    $request = new Request();
+    $request->attributes->set(RouteObjectInterface::ROUTE_NAME, 'example3');
+    $request->attributes->set(RouteObjectInterface::ROUTE_OBJECT, $route);
+    $this->container->get('request_stack')->push($request);
+    $active_trail_expectations = [];
+    $active_trail_expectations['all'] = <<<EOF
+test.example1
+test.example2
+  |- test.example3
+    |- test.example4
+test.example5
+  |- test.example7
+test.example6
+test.example8
+
+EOF;
+    $active_trail_expectations['level_1_only'] = <<<EOF
+test.example1
+test.example2
+test.example5
+test.example6
+test.example8
+
+EOF;
+    $active_trail_expectations['level_2_only'] = <<<EOF
+test.example3
+test.example7
+
+EOF;
+    $active_trail_expectations['level_3_only'] = <<<EOF
+test.example4
+
+EOF;
+
+    $active_trail_expectations['level_1_and_beyond'] = $active_trail_expectations['all'];
+    $active_trail_expectations['level_2_and_beyond'] = <<<EOF
+test.example3
+  |- test.example4
+test.example7
+
+EOF;
+    $active_trail_expectations['level_3_and_beyond'] = $active_trail_expectations['level_3_only'];
+    foreach ($blocks as $id => $block) {
+      $this->assertIdentical($active_trail_expectations[$id], $asciify($block->build()), format_string('Menu block %id with an active trail renders the expected tree.', ['%id' => $id]));
+    }
+  }
+
 }
diff --git a/core/profiles/minimal/config/install/block.block.stark_admin.yml b/core/profiles/minimal/config/install/block.block.stark_admin.yml
index a7cc0a5..0934049 100644
--- a/core/profiles/minimal/config/install/block.block.stark_admin.yml
+++ b/core/profiles/minimal/config/install/block.block.stark_admin.yml
@@ -10,6 +10,11 @@ settings:
   label: Administration
   provider: system
   label_display: visible
+  cache:
+    max_age: -1
+    contexts: {  }
+  level: 1
+  depth: 0
 dependencies:
   entity:
     - system.menu.admin
diff --git a/core/profiles/minimal/config/install/block.block.stark_tools.yml b/core/profiles/minimal/config/install/block.block.stark_tools.yml
index aeb99bb..c8268bb 100644
--- a/core/profiles/minimal/config/install/block.block.stark_tools.yml
+++ b/core/profiles/minimal/config/install/block.block.stark_tools.yml
@@ -10,6 +10,11 @@ settings:
   label: Tools
   provider: system
   label_display: visible
+  cache:
+    max_age: -1
+    contexts: {  }
+  level: 1
+  depth: 0
 dependencies:
   entity:
     - system.menu.tools
diff --git a/core/profiles/standard/config/install/block.block.bartik_footer.yml b/core/profiles/standard/config/install/block.block.bartik_footer.yml
index 26acc46..3074b3a 100644
--- a/core/profiles/standard/config/install/block.block.bartik_footer.yml
+++ b/core/profiles/standard/config/install/block.block.bartik_footer.yml
@@ -11,6 +11,11 @@ settings:
   label: 'Footer menu'
   provider: system
   label_display: visible
+  cache:
+    max_age: -1
+    contexts: {  }
+  level: 1
+  depth: 0
 dependencies:
   entity:
     - system.menu.footer
diff --git a/core/profiles/standard/config/install/block.block.bartik_tools.yml b/core/profiles/standard/config/install/block.block.bartik_tools.yml
index 6ed6808..9a4b8b3 100644
--- a/core/profiles/standard/config/install/block.block.bartik_tools.yml
+++ b/core/profiles/standard/config/install/block.block.bartik_tools.yml
@@ -11,6 +11,11 @@ settings:
   label: Tools
   provider: system
   label_display: visible
+  cache:
+    max_age: -1
+    contexts: {  }
+  level: 1
+  depth: 0
 dependencies:
   entity:
     - system.menu.tools
