diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index bfd1aaf..adbe5ae 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -1763,20 +1763,38 @@ function theme_mark($variables) {
 }
 
 /**
- * Preprocesses variables for theme_item_list().
+ * Prepares variables for item list templates.
+ *
+ * Default template: item-list.html.twig.
  *
  * @param array $variables
- *   An associative array containing theme variables for theme_item_list().
- *   'items' in variables will be preprocessed to automatically inherit the
- *   variables of this list to any possibly contained nested lists that do not
- *   specify custom render properties. This allows callers to specify larger
- *   nested lists, without having to explicitly specify and repeat the render
- *   properties for all nested child lists.
+ *   An associative array containing:
+ *   - items: An array of items to be displayed in the list. Each item can be
+ *     either a string or a render array. If #type, #theme, or #markup
+ *     properties are not specified for child render arrays, they will be
+ *     inherited from the parent list, allowing callers to specify larger
+ *     nested lists without having to explicitly specify and repeat the
+ *     render properties for all nested child lists.
+ *   - title: A title to be prepended to the list.
+ *   - list_type: The type of list to return (e.g. "ul", "ol").
+ *
+ * @see http://drupal.org/node/1842756
  */
 function template_preprocess_item_list(&$variables) {
+  $variables['title'] = (string) $variables['title'];
+
+  // Prepare for adding classes to each item.
+  $num_items = count($variables['items']);
+  $i = 0;
   foreach ($variables['items'] as &$item) {
+    $i++;
+    $attributes = array();
     // If the item value is an array, then it is a render array.
     if (is_array($item)) {
+      // List items support attributes via the #wrapper_attributes property.
+      if (isset($item['#wrapper_attributes']) && is_array($item['#wrapper_attributes'])) {
+        $attributes = $item['#wrapper_attributes'];
+      }
       // Determine whether there are any child elements in the item that are not
       // fully-specified render arrays. If there are any, then the child
       // elements present nested lists and we automatically inherit the render
@@ -1806,60 +1824,23 @@ function template_preprocess_item_list(&$variables) {
         }
       }
     }
-  }
-}
-
-/**
- * Returns HTML for a list or nested list of items.
- *
- * @param $variables
- *   An associative array containing:
- *   - items: A list of items to render. Allowed values are strings or
- *     render arrays. Render arrays can specify list item attributes in the
- *     #wrapper_attributes property.
- *   - title: The title of the list.
- *   - list_type: The type of HTML list (e.g. "ul", "ol").
- *   - attributes: The attributes applied to the list element.
- *   - empty: A message to display when there are no items. Allowed value is a
- *     string or render array.
- */
-function theme_item_list($variables) {
-  $items = $variables['items'];
-  $title = (string) $variables['title'];
-  $list_type = $variables['list_type'];
-  $list_attributes = $variables['attributes'];
-
-  $output = '';
-  if ($items) {
-    $output .= '<' . $list_type . new Attribute($list_attributes) . '>';
-
-    foreach ($items as &$item) {
-      $attributes = array();
-      if (is_array($item)) {
-        if (isset($item['#wrapper_attributes'])) {
-          $attributes = $item['#wrapper_attributes'];
-        }
-        $item = drupal_render($item);
-      }
-      $output .= '<li' . new Attribute($attributes) . '>' . $item . '</li>';
+    else {
+      // Turn the item into an array if it wasn't one already.
+      $item = array('#markup' => $item);
     }
-    $output .= "</$list_type>";
-  }
-  elseif (!empty($variables['empty'])) {
-    $output .= render($variables['empty']);
-  }
-
-  // Only output the list container and title, if there are any list items.
-  // Check to see whether the block title exists before adding a header.
-  // Empty headers are not semantic and present accessibility challenges.
-  if ($output !== '') {
-    if ($title !== '') {
-      $title = '<h3>' . $title . '</h3>';
+    $attributes['class'][] = ($i % 2 ? 'odd' : 'even');
+    if ($i == 1) {
+      $attributes['class'][] = 'first';
+    }
+    if ($i == $num_items) {
+      $attributes['class'][] = 'last';
     }
-    $output = '<div class="item-list">' . $title . $output . '</div>';
-  }
 
-  return $output;
+    // In order to avoid '..is not a valid render element' errors in render(),
+    // use the #-prefixed #wrapper_attributes property to store item wrapper
+    // attributes for Twig.
+    $item['#wrapper_attributes'] = new Attribute($attributes);
+  }
 }
 
 /**
@@ -2637,6 +2618,7 @@ function drupal_common_theme() {
     ),
     'item_list' => array(
       'variables' => array('items' => array(), 'title' => '', 'list_type' => 'ul', 'attributes' => array(), 'empty' => NULL),
+      'template' => 'item-list',
     ),
     'feed_icon' => array(
       'variables' => array('url' => NULL, 'title' => NULL),
diff --git a/core/modules/system/templates/item-list.html.twig b/core/modules/system/templates/item-list.html.twig
new file mode 100644
index 0000000..de827b0
--- /dev/null
+++ b/core/modules/system/templates/item-list.html.twig
@@ -0,0 +1,43 @@
+{#
+/**
+ * @file
+ * Default theme implementation for an item list.
+ *
+ * Available variables:
+ * - items: A list of renderable items. Each item has a #wrapper_attributes
+ *   property which contains any HTML attributes which should be applied to the
+ *   <li> tag.
+ * - title: The title of the list.
+ * - list_type: The tag for list element ("ul" or "ol").
+ * - attributes: HTML attributes to be applied to the list.
+ * - empty: A message to display when there are no items. Allowed value is a
+ *   string or render array.
+ *
+ * @see template_preprocess_item_list()
+ *
+ * @ingroup themeable
+ */
+#}
+{%- if items or empty -%}
+<div class="item-list">
+  {%- if title -%}
+    <h3>{{ title }}</h3>
+  {%- endif -%}
+  {%- if items -%}
+    {%- if list_type == 'ul' -%}
+      <ul{{ attributes }}>
+    {%- else -%}
+      <ol{{ attributes }}>
+    {%- endif %}
+      {%- for item in items -%}
+        <li{{ item['#wrapper_attributes'] }}>{{ item }}</li>
+      {%- endfor -%}
+    {%- if list_type == 'ul' -%}
+      </ul>
+    {%- else -%}
+      </ol>
+    {%- endif %}
+  {%- endif -%}
+  {{- empty -}}
+</div>
+{%- endif %}
