diff --git a/core/includes/module.inc b/core/includes/module.inc
index f65f0b8..0f1b0d8 100644
--- a/core/includes/module.inc
+++ b/core/includes/module.inc
@@ -45,7 +45,7 @@ function system_list($type) {
     \Drupal::cache('bootstrap')->set('system_list', $lists);
   }
   // To avoid a separate database lookup for the filepath, prime the
-  // drupal_get_filename() static cache with all enabled modules and themes.
+  // drupal_get_filename() static cache with all enabled themes.
   foreach ($lists['filepaths'] as $item) {
     system_register($item['type'], $item['name'], $item['filepath']);
   }
diff --git a/core/lib/Drupal/Core/Extension/ModuleHandler.php b/core/lib/Drupal/Core/Extension/ModuleHandler.php
index bb79ae4..a06f8ba 100644
--- a/core/lib/Drupal/Core/Extension/ModuleHandler.php
+++ b/core/lib/Drupal/Core/Extension/ModuleHandler.php
@@ -711,7 +711,7 @@ public function getModuleDirectories() {
    */
   public function getName($module) {
     $module_data = system_rebuild_module_data();
-    return $module_data[$module]->info['name'];
+    return isset($module_data[$module]->info['name']) ? $module_data[$module]->info['name']) : $module;
   }
 
 }
diff --git a/core/lib/Drupal/Core/Extension/ModuleHandlerInterface.php b/core/lib/Drupal/Core/Extension/ModuleHandlerInterface.php
index 9d12df6..43e3b5e 100644
--- a/core/lib/Drupal/Core/Extension/ModuleHandlerInterface.php
+++ b/core/lib/Drupal/Core/Extension/ModuleHandlerInterface.php
@@ -307,7 +307,8 @@ public function getModuleDirectories();
    *   The machine name of the module which title should be shown.
    *
    * @return string
-   *   Returns the human readable name of the module.
+   *   Returns the human readable name of the module or the machine name passed
+   *   in if no matching module is found.
    */
   public function getName($module);
 
diff --git a/core/lib/Drupal/Core/Menu/Form/MenuLinkDefaultForm.php b/core/lib/Drupal/Core/Menu/Form/MenuLinkDefaultForm.php
index bf86365..1062b2b 100644
--- a/core/lib/Drupal/Core/Menu/Form/MenuLinkDefaultForm.php
+++ b/core/lib/Drupal/Core/Menu/Form/MenuLinkDefaultForm.php
@@ -108,7 +108,7 @@ public function buildConfigurationForm(array $form, FormStateInterface $form_sta
     $provider = $this->menuLink->getProvider();
     $form['info'] = array(
       '#type' => 'item',
-      '#title' => $this->t('This link is provided by the @name module. The title and path cannot be edited.', array('@name' => $this->getModuleName($provider))),
+      '#title' => $this->t('This link is provided by the @name module. The title and path cannot be edited.', array('@name' => $this->moduleHandler->getName($provider))),
     );
     $link = array(
       '#type' => 'link',
@@ -187,31 +187,4 @@ public function submitConfigurationForm(array &$form, FormStateInterface $form_s
     return $this->menuLinkManager->updateDefinition($this->menuLink->getPluginId(), $new_definition);
   }
 
-  /**
-   * Gets the name of the module.
-   *
-   * @param string $module
-   *   The machine name of a module.
-   *
-   * @todo This function is horrible, but core has nothing better until we add a
-   * a method to the ModuleHandler that handles this nicely.
-   * https://drupal.org/node/2281989
-   *
-   * @return string
-   *   The human-readable, localized module name, or the machine name passed in
-   *   if no matching module is found.
-   */
-  protected function getModuleName($module) {
-    // Gather module data.
-    if (!isset($this->moduleData)) {
-      $this->moduleData = system_get_info('module');
-    }
-    // If the module exists, return its human-readable name.
-    if (isset($this->moduleData[$module])) {
-      return $this->t($this->moduleData[$module]['name']);
-    }
-    // Otherwise, return the machine name.
-    return $module;
-  }
-
 }
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index d2bda7f..41db7cc 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -854,7 +854,9 @@ function system_check_directory($form_element, FormStateInterface $form_state) {
 function system_get_info($type, $name = NULL) {
   $info = array();
   if ($type == 'module') {
-    $data = system_rebuild_module_data();
+    if (!$data = \Drupal::state()->get('system.module.data')) {
+      $data = system_rebuild_module_data();
+    }
     foreach (\Drupal::moduleHandler()->getModuleList() as $module => $filename) {
       if (isset($data[$module])) {
         $info[$module] = $data[$module]->info;
@@ -997,9 +999,14 @@ function system_rebuild_module_data() {
       $files[$name] = $module->getPathname();
     }
     $modules = \Drupal::moduleHandler()->buildModuleDependencies($modules);
+    // Store the module info in state. We rely on consecutive calls to
+    // system_rebuild_module_data() to reset this key, such as when
+    // listing modules, (un)installating modules, importing configuration,
+    // updating the site and when flushing all caches.
+    \Drupal::state()->set('system.module.data', $modules);
     $modules_cache = $modules;
 
-    // Store filenames to allow system_list() and drupal_get_filename() to
+    // Store filenames to allow drupal_get_filename() to
     // retrieve them without having to rebuild or scan the filesystem.
     \Drupal::state()->set('system.module.files', $files);
   }
