diff --git a/core/modules/menu_ui/menu_ui.module b/core/modules/menu_ui/menu_ui.module
index 8dbb4e2..3f0515e 100644
--- a/core/modules/menu_ui/menu_ui.module
+++ b/core/modules/menu_ui/menu_ui.module
@@ -139,10 +139,8 @@ function menu_ui_menu_delete(Menu $menu) {
  * Implements hook_block_view_BASE_BLOCK_ID_alter() for 'system_menu_block'.
  */
 function menu_ui_block_view_system_menu_block_alter(array &$build, BlockPluginInterface $block) {
-  // Add contextual links for system menu blocks.
-  $menus = menu_list_system_menus();
-  $menu_name = $block->getDerivativeId();
-  if (isset($menus[$menu_name]) && isset($build['content'])) {
+  if ($block->getBaseId() == 'system_menu_block') {
+    $menu_name = $block->getDerivativeId();
     $build['#contextual_links']['menu'] = array(
       'route_parameters' => array('menu' => $menu_name),
     );
diff --git a/core/modules/system/src/Plugin/Block/SystemMenuBlock.php b/core/modules/system/src/Plugin/Block/SystemMenuBlock.php
index 258ffbb..59b3fe0 100644
--- a/core/modules/system/src/Plugin/Block/SystemMenuBlock.php
+++ b/core/modules/system/src/Plugin/Block/SystemMenuBlock.php
@@ -9,7 +9,9 @@
 
 use Drupal\Component\Utility\NestedArray;
 use Drupal\block\BlockBase;
+use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Menu\MenuActiveTrailInterface;
 use Drupal\Core\Menu\MenuLinkTreeInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -28,6 +30,13 @@
 class SystemMenuBlock extends BlockBase implements ContainerFactoryPluginInterface {
 
   /**
+   * Stores the configuration factory.
+   *
+   * @var \Drupal\Core\Config\ConfigFactoryInterface;
+   */
+  protected $configFactory;
+
+  /**
    * The menu link tree service.
    *
    * @var \Drupal\Core\Menu\MenuLinkTreeInterface
@@ -50,13 +59,16 @@ class SystemMenuBlock extends BlockBase implements ContainerFactoryPluginInterfa
    *   The plugin_id for the plugin instance.
    * @param array $plugin_definition
    *   The plugin implementation definition.
+   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
+   *   The factory for configuration objects.
    * @param \Drupal\Core\Menu\MenuLinkTreeInterface $menu_tree
    *   The menu tree service.
    * @param \Drupal\Core\Menu\MenuActiveTrailInterface $menu_active_trail
    *   The active menu trail service.
    */
-  public function __construct(array $configuration, $plugin_id, $plugin_definition, MenuLinkTreeInterface $menu_tree, MenuActiveTrailInterface $menu_active_trail) {
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, ConfigFactoryInterface $config_factory, MenuLinkTreeInterface $menu_tree, MenuActiveTrailInterface $menu_active_trail) {
     parent::__construct($configuration, $plugin_id, $plugin_definition);
+    $this->configFactory = $config_factory;
     $this->menuTree = $menu_tree;
     $this->menuActiveTrail = $menu_active_trail;
   }
@@ -69,6 +81,7 @@ public static function create(ContainerInterface $container, array $configuratio
       $configuration,
       $plugin_id,
       $plugin_definition,
+      $container->get('config.factory'),
       $container->get('menu.link_tree'),
       $container->get('menu.active_trail')
     );
@@ -77,10 +90,90 @@ public static function create(ContainerInterface $container, array $configuratio
   /**
    * {@inheritdoc}
    */
+  public function defaultConfiguration() {
+    // Modify the default max age for menu blocks: modifications made to menus,
+    // menu links and menu blocks will automatically invalidate corresponding
+    // cache tags, therefore allowing us to cache menu blocks forever. This is
+    // only not the case if there are user-specific or dynamic alterations (e.g.
+    // hook_node_access()), but in that:
+    // 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),
+      'level' => 1,
+      'depth' => 0,
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function blockForm($form, FormStateInterface $form_state) {
+     $config = $this->configuration;
+
+     $form['level'] = array(
+       '#type' => 'select',
+       '#title' => $this->t('Starting level'),
+       '#default_value' => $config['level'],
+       '#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'),
+       ),
+       '#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,
+     );
+
+     $form['depth'] = array(
+       '#type' => 'select',
+       '#title' => $this->t('Depth'),
+       '#default_value' => $config['depth'],
+       '#options' => array(
+         '1'  => '1',
+         '2'  => '2',
+         '3'  => '3',
+         '4'  => '4',
+         '5'  => '5',
+         '6'  => '6',
+         '7'  => '7',
+         '8'  => '8',
+         '9'  => '9',
+         '0'  => $this->t('Unlimited'),
+       ),
+       '#description' => $this->t('Specify the maximum number of levels of the menu tree to display.'),
+       '#required' => TRUE,
+     );
+
+     return $form;
+   }
+
+  /**
+   * {@inheritdoc}
+   */
   public function build() {
     $menu_name = $this->getDerivativeId();
+
+    $config = $this->configuration;
+    $level = $config['level'];
+    $depth = $config['depth'];
+
     $parameters = $this->menuTree->getCurrentRouteMenuTreeParameters($menu_name);
+
+    // Determine the max depth based on level and depth setting.
+    $max_depth = ($depth == 0) ? NULL : min($level + $depth - 1, $this->menuTree->maxDepth());
+
+    $parameters->setMinDepth($level);
+    $parameters->setMaxDepth($max_depth);
+
     $tree = $this->menuTree->load($menu_name, $parameters);
+
     $manipulators = array(
       array('callable' => 'menu.default_tree_manipulators:checkAccess'),
       array('callable' => 'menu.default_tree_manipulators:generateIndexAndSort'),
@@ -92,21 +185,6 @@ public function build() {
   /**
    * {@inheritdoc}
    */
-  public function defaultConfiguration() {
-    // Modify the default max age for menu blocks: modifications made to menus,
-    // menu links and menu blocks will automatically invalidate corresponding
-    // cache tags, therefore allowing us to cache menu blocks forever. This is
-    // only not the case if there are user-specific or dynamic alterations (e.g.
-    // hook_node_access()), but in that:
-    // 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));
-  }
-
-  /**
-   * {@inheritdoc}
-   */
   public function getCacheKeys() {
     // Add a key for the active menu trail.
     $menu = $this->getDerivativeId();
