diff --git a/core/includes/common.inc b/core/includes/common.inc
index 919bfb5..c5d4cb0 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -2286,12 +2286,6 @@ function l($text, $path, array $options = array()) {
     $options['attributes']['class'][] = 'active';
   }
 
-  // Remove all HTML and PHP tags from a tooltip. For best performance, we act only
-  // if a quick strpos() pre-check gave a suspicion (because strip_tags() is expensive).
-  if (isset($options['attributes']['title']) && strpos($options['attributes']['title'], '<') !== FALSE) {
-    $options['attributes']['title'] = strip_tags($options['attributes']['title']);
-  }
-
   // Determine if rendering of the link is to be done with a theme function
   // or the inline default. Inline is faster, but if the theme system has been
   // loaded and a module or theme implements a preprocess or process function
diff --git a/core/includes/menu.inc b/core/includes/menu.inc
index f23eb0d..59beb4d 100644
--- a/core/includes/menu.inc
+++ b/core/includes/menu.inc
@@ -696,13 +696,13 @@ function _menu_item_localize(&$item, $map, $link_translate = FALSE) {
   }
 
   // Translate description, see the motivation above.
-  if (!empty($item['description'])) {
-    $original_description = $item['description'];
+  if (!$link_translate || ($item['description'] == $item['link_description'])) {
     $item['description'] = t($item['description']);
-    if ($link_translate && isset($item['options']['attributes']['title']) && $item['options']['attributes']['title'] == $original_description) {
-      $item['localized_options']['attributes']['title'] = $item['description'];
-    }
   }
+  elseif ($link_translate) {
+    $item['description'] = $item['link_description'];
+  }
+
 }
 
 /**
@@ -1043,6 +1043,8 @@ function menu_tree_output($tree) {
       $data['link']['localized_options']['attributes']['class'][] = 'active';
     }
 
+    $data['link']['localized_options']['attributes']['title'] = decode_entities(strip_tags($data['link']['description']));
+
     // Allow menu-specific theme overrides.
     $element['#theme'] = 'menu_link__' . strtr($data['link']['menu_name'], '-', '_');
     $element['#attributes']['class'] = $class;
@@ -2717,9 +2719,10 @@ function _menu_link_build($item) {
   $item += array(
     'menu_name' => 'navigation',
     'link_title' => $item['title'],
+    'link_description' => $item['description'],
     'link_path' => $item['path'],
     'hidden' => 0,
-    'options' => empty($item['description']) ? array() : array('attributes' => array('title' => $item['description'])),
+    'options' => empty($item['description']) ? array() : array('attributes' => array('title' => decode_entities(strip_tags($item['description'])))),
   );
   return $item;
 }
@@ -2990,6 +2993,7 @@ function menu_link_save(&$item, $existing_item = array(), $parent_candidates = a
     'menu_name' => 'navigation',
     'weight' => 0,
     'link_title' => '',
+    'link_description' => '',
     'hidden' => 0,
     'has_children' => 0,
     'expanded' => 0,
@@ -3035,6 +3039,7 @@ function menu_link_save(&$item, $existing_item = array(), $parent_candidates = a
         'weight' => $item['weight'],
         'module' => $item['module'],
         'link_title' => $item['link_title'],
+        'link_description' => $item['link_description'],
         'options' => serialize($item['options']),
         'customized' => $item['customized'],
         'updated' => $item['updated'],
@@ -3109,6 +3114,7 @@ function menu_link_save(&$item, $existing_item = array(), $parent_candidates = a
         'p9' => $item['p9'],
         'module' => $item['module'],
         'link_title' => $item['link_title'],
+        'link_description' => $item['link_description'],
         'options' => serialize($item['options']),
         'customized' => $item['customized'],
       ))
diff --git a/core/modules/book/book.module b/core/modules/book/book.module
index 1080984..dc9fc44 100644
--- a/core/modules/book/book.module
+++ b/core/modules/book/book.module
@@ -271,6 +271,7 @@ function book_block_view($delta = '') {
         $book_node = node_load($book['nid']);
         $book['access'] = node_access('view', $book_node);
         $pseudo_tree[0]['link'] = $book;
+        $pseudo_tree[0]['link']['description'] = '';
         $book_menus[$book_id] = menu_tree_output($pseudo_tree);
       }
     }
@@ -1284,7 +1285,7 @@ function book_menu_subtree_data($link) {
       $query->join('menu_router', 'm', 'm.path = ml.router_path');
       $query->join('book', 'b', 'ml.mlid = b.mlid');
       $query->fields('b');
-      $query->fields('m', array('load_functions', 'to_arg_functions', 'access_callback', 'access_arguments', 'page_callback', 'page_arguments', 'delivery_callback', 'title', 'title_callback', 'title_arguments', 'type'));
+      $query->fields('m', array('load_functions', 'to_arg_functions', 'access_callback', 'access_arguments', 'page_callback', 'page_arguments', 'delivery_callback', 'title', 'title_callback', 'title_arguments', 'description', 'type'));
       $query->fields('ml');
       $query->condition('menu_name', $link['menu_name']);
       for ($i = 1; $i <= MENU_MAX_DEPTH && $link["p$i"]; ++$i) {
diff --git a/core/modules/menu/menu.admin.inc b/core/modules/menu/menu.admin.inc
index f933feb..e8b47a6 100644
--- a/core/modules/menu/menu.admin.inc
+++ b/core/modules/menu/menu.admin.inc
@@ -258,7 +258,20 @@ function theme_menu_overview_form($variables) {
 function menu_edit_item($form, &$form_state, $type, $item, $menu) {
   if ($type == 'add' || empty($item)) {
     // This is an add form, initialize the menu link.
-    $item = array('link_title' => '', 'mlid' => 0, 'plid' => 0, 'menu_name' => $menu['menu_name'], 'weight' => 0, 'link_path' => '', 'options' => array(), 'module' => 'menu', 'expanded' => 0, 'hidden' => 0, 'has_children' => 0);
+    $item = array(
+      'link_title' => '',
+      'mlid' => 0,
+      'plid' => 0,
+      'menu_name' => $menu['menu_name'],
+      'weight' => 0,
+      'link_path' => '',
+      'options' => array(),
+      'link_description' => '',
+      'module' => 'menu',
+      'expanded' => 0,
+      'hidden' => 0,
+      'has_children' => 0,
+    );
   }
   $form['actions'] = array('#type' => 'actions');
   $form['link_title'] = array(
@@ -306,10 +319,10 @@ function menu_edit_item($form, &$form_state, $type, $item, $menu) {
       '#description' => l($item['link_title'], $item['href'], $item['options']),
     );
   }
-  $form['description'] = array(
+  $form['link_description'] = array(
     '#type' => 'textarea',
     '#title' => t('Description'),
-    '#default_value' => isset($item['options']['attributes']['title']) ? $item['options']['attributes']['title'] : '',
+    '#default_value' => $item['link_description'],
     '#rows' => 1,
     '#description' => t('Shown when hovering over the menu link.'),
   );
@@ -404,8 +417,6 @@ function menu_edit_item_submit($form, &$form_state) {
   // supplied by the "enabled" checkbox.
   $item['hidden'] = (int) !$item['enabled'];
   unset($item['enabled']);
-
-  $item['options']['attributes']['title'] = $item['description'];
   list($item['menu_name'], $item['plid']) = explode(':', $item['parent']);
   if (!menu_link_save($item)) {
     drupal_set_message(t('There was an error saving the menu link.'), 'error');
diff --git a/core/modules/menu/menu.test b/core/modules/menu/menu.test
index 08bb7e8..c5c556f 100644
--- a/core/modules/menu/menu.test
+++ b/core/modules/menu/menu.test
@@ -292,7 +292,7 @@ class MenuTestCase extends DrupalWebTestCase {
     $edit = array(
       'link_path' => $link,
       'link_title' => $title,
-      'description' => '',
+      'link_description' => '',
       'enabled' => TRUE, // Use this to disable the menu and test.
       'expanded' => TRUE, // Setting this to true should test whether it works when we do the std_user tests.
       'parent' =>  $menu_name . ':' . $plid,
diff --git a/core/modules/system/system.admin.inc b/core/modules/system/system.admin.inc
index aa2f98f..11788c8 100644
--- a/core/modules/system/system.admin.inc
+++ b/core/modules/system/system.admin.inc
@@ -25,10 +25,9 @@ function system_admin_config_page() {
       if (!$item['access']) {
         continue;
       }
-      // The link description, either derived from 'description' in hook_menu()
-      // or customized via menu module is used as title attribute.
       if (!empty($item['localized_options']['attributes']['title'])) {
-        $item['description'] = $item['localized_options']['attributes']['title'];
+        // The title attribute is unset to reduce redundancy in admin pages for
+        // screen readers.
         unset($item['localized_options']['attributes']['title']);
       }
       $block = $item;
diff --git a/core/modules/system/system.install b/core/modules/system/system.install
index 6711471..e5e7329 100644
--- a/core/modules/system/system.install
+++ b/core/modules/system/system.install
@@ -1138,13 +1138,18 @@ function system_schema() {
         'default' => '',
       ),
       'link_title' => array(
-      'description' => 'The text displayed for the link, which may be modified by a title callback stored in {menu_router}.',
+        'description' => 'The text displayed for the link, which may be modified by a title callback stored in {menu_router}.',
         'type' => 'varchar',
         'length' => 255,
         'not null' => TRUE,
         'default' => '',
         'translatable' => TRUE,
       ),
+      'link_description' => array(
+        'description' => 'A description of this item.',
+        'type' => 'text',
+        'not null' => FALSE,
+      ),
       'options' => array(
         'description' => 'A serialized array of options to be passed to the url() or l() function, such as a query string or HTML attributes.',
         'type' => 'blob',
@@ -1642,6 +1647,29 @@ function system_update_8001() {
 }
 
 /**
+ * Add link_description column to {menu_links}.
+ */
+function system_update_8002() {
+  db_drop_field('menu_links', 'link_description');
+  db_add_field('menu_links', 'link_description', array('description' => 'A description of this item.', 'type' => 'text', 'not null' => FALSE));
+  $result = db_query('SELECT mlid, options FROM {menu_links} WHERE options <> :empty', array(':empty' => serialize(array())));
+  foreach ($result as $menu_link) {
+    $options = unserialize($menu_link->options);
+    if (isset($options['attributes']['title'])) {
+      $link_description = $options['attributes']['title'];
+      unset($options['attributes']['title']);
+      if (empty($options['attributes'])) {
+        unset($options['attributes']);
+      }
+      db_query('UPDATE {menu_links} SET link_description = :link_description, options = :options WHERE mlid = :mlid', array(
+        ':link_description' => $link_description,
+        ':options' => serialize($options),
+        ':mlid' => $menu_link->mlid));
+    }
+  }
+}
+
+/**
  * @} End of "defgroup updates-7.x-to-8.x"
  * The next series of updates should start at 9000.
  */
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index f16b73f..ea3db30 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -2133,12 +2133,6 @@ function system_admin_menu_block($item) {
   foreach ($query->execute() as $link) {
     _menu_link_translate($link);
     if ($link['access']) {
-      // The link description, either derived from 'description' in
-      // hook_menu() or customized via menu module is used as title attribute.
-      if (!empty($link['localized_options']['attributes']['title'])) {
-        $link['description'] = $link['localized_options']['attributes']['title'];
-        unset($link['localized_options']['attributes']['title']);
-      }
       // Prepare for sorting as in function _menu_tree_check_access().
       // The weight is offset so it is always positive, with a uniform 5-digits.
       $key = (50000 + $link['weight']) . ' ' . drupal_strtolower($link['title']) . ' ' . $link['mlid'];
diff --git a/core/modules/toolbar/toolbar.module b/core/modules/toolbar/toolbar.module
index d25ca2d..d4caafa 100644
--- a/core/modules/toolbar/toolbar.module
+++ b/core/modules/toolbar/toolbar.module
@@ -311,7 +311,7 @@ function toolbar_menu_navigation_links($tree) {
       $link['attributes'] = array('id' => 'toolbar-link-' . $id);
       if (!empty($item['link']['description'])) {
         $link['title'] .= ' <span class="element-invisible">(' . $item['link']['description'] . ')</span>';
-        $link['attributes']['title'] = $item['link']['description'];
+        $link['attributes']['title'] = decode_entities(strip_tags($item['link']['description']));
       }
       $link['html'] = TRUE;
 
