diff --git a/includes/common.inc b/includes/common.inc
index d64be82..7dc68fd 100644
--- a/includes/common.inc
+++ b/includes/common.inc
@@ -6435,6 +6435,9 @@ function drupal_common_theme() {
     'links' => array(
       'variables' => array('links' => NULL, 'attributes' => array('class' => array('links')), 'heading' => array()),
     ),
+    'wrap_links' => array(
+      'render element' => 'elements',
+    ),
     'image' => array(
       // HTML 4 and XHTML 1.0 always require an alt attribute. The HTML 5 draft
       // allows the alt attribute to be omitted in some cases. Therefore,
diff --git a/includes/theme.inc b/includes/theme.inc
index bea87c0..4168227 100644
--- a/includes/theme.inc
+++ b/includes/theme.inc
@@ -1510,6 +1510,27 @@ function theme_link($variables) {
 }
 
 /**
+ * Converts rendered sub-elements of #type 'links' into #items.
+ */
+function theme_wrap_links($variables) {
+  $elements = &$variables['elements'];
+  foreach (element_children($elements) as $key) {
+    // Children are only rendered if the current user has access.
+    if (isset($elements[$key]['#children'])) {
+      $elements['#items'][$key] = $elements[$key]['#children'];
+    }
+  }
+  // 'type' is most probably the most stupid theme variable ever.
+  $elements['#type'] = $elements['#tag'];
+
+  $hook = 'item_list';
+  if (!empty($elements['#theme_pattern'])) {
+    $hook .= '__' . $elements['#theme_pattern'];
+  }
+  return theme($hook, $elements);
+}
+
+/**
  * Returns HTML for a set of links.
  *
  * @param $variables
diff --git a/modules/node/node.module b/modules/node/node.module
index 0c3cfb7..4b0aad1 100644
--- a/modules/node/node.module
+++ b/modules/node/node.module
@@ -2590,6 +2590,20 @@ function node_page_default() {
       '#prefix' => '<div id="first-time">',
       '#suffix' => '</div>',
     );
+    $build['links'] = array(
+      '#type' => 'links',
+    );
+    $build['links']['foo'] = array(
+      '#type' => 'link',
+      '#title' => t('Foo (last)'),
+      '#href' => 'foo',
+      '#weight' => 10,
+    );
+    $build['links']['bar'] = array(
+      '#type' => 'link',
+      '#title' => t('Bar'),
+      '#href' => 'bar',
+    );
   }
   return $build;
 }
diff --git a/modules/system/system.module b/modules/system/system.module
index 0ef688e..8d0d8f0 100644
--- a/modules/system/system.module
+++ b/modules/system/system.module
@@ -471,6 +471,23 @@ function system_element_info() {
     '#markup' => '',
     '#pre_render' => array('drupal_pre_render_markup'),
   );
+  $types['links'] = array(
+    // Using a key to allow for easy access to add a theme sub-pattern.
+    '#theme_wrappers' => array('wrap_links'),
+    // Originally attempted to use two #theme_wrappers; one for converting
+    // sub-elements into #items on the $element, and then a second one being the
+    // actual, usual theme function - so you could have specified subpatterns
+    // à la 'item_list__operations'. However, a theme() function is not able to
+    // change the passed in $variables by reference (and hence changes to
+    // $element are not visible). The idea is to have the sub-elements (list
+    // items) being rendered as usual, relying on native drupal_render() only,
+    // without doing a hack à la #pre_render that shortcuts the processing.
+    // Hence, use #theme_pattern to optionally specify the trailing '__variant'
+    // without '__'.
+    '#theme_pattern' => NULL,
+    '#tag' => 'ul',
+    '#attributes' => array('class' => array('links', 'inline')),
+  );
   $types['link'] = array(
     '#pre_render' => array('drupal_pre_render_link', 'drupal_pre_render_markup'),
   );
