diff --git a/core/includes/tablesort.inc b/core/includes/tablesort.inc
index cd5c0c1..0b3574f 100644
--- a/core/includes/tablesort.inc
+++ b/core/includes/tablesort.inc
@@ -30,27 +30,26 @@ function tablesort_init($header) {
  * If the cell in question is the column header for the current sort criterion,
  * it gets special formatting. All possible sort criteria become links.
  *
- * @param $cell
- *   The cell to format.
- * @param $header
+ * @param string $cell_content
+ *   The cell content to format. Passed by reference.
+ * @param array $cell_attributes
+ *   The cell attributes. Passed by reference.
+ * @param array $header
  *   An array of column headers in the format described in '#type' => 'table'.
- * @param $ts
+ * @param array $ts
  *   The current table sort context as returned from tablesort_init().
- *
- * @return
- *   A properly formatted cell, ready for _theme_table_cell().
  */
-function tablesort_header($cell, $header, $ts) {
+function tablesort_header(&$cell_content, array &$cell_attributes, array $header, array $ts) {
   // Special formatting for the currently sorted column header.
-  if (is_array($cell) && isset($cell['field'])) {
-    $title = t('sort by @s', array('@s' => $cell['data']));
-    if ($cell['data'] == $ts['name']) {
+  if (isset($cell_attributes['field'])) {
+    $title = t('sort by @s', array('@s' => $cell_content));
+    if ($cell_content == $ts['name']) {
       // aria-sort is a WAI-ARIA property that indicates if items in a table
       // or grid are sorted in ascending or descending order. See
       // http://www.w3.org/TR/wai-aria/states_and_properties#aria-sort
-      $cell['aria-sort'] = ($ts['sort'] == 'asc') ? 'ascending' : 'descending';
+      $cell_attributes['aria-sort'] = ($ts['sort'] == 'asc') ? 'ascending' : 'descending';
       $ts['sort'] = (($ts['sort'] == 'asc') ? 'desc' : 'asc');
-      $cell['class'][] = 'active';
+      $cell_attributes['class'][] = 'active';
       $tablesort_indicator = array(
         '#theme' => 'tablesort_indicator',
         '#style' => $ts['sort'],
@@ -62,40 +61,17 @@ function tablesort_header($cell, $header, $ts) {
       $ts['sort'] = 'asc';
       $image = '';
     }
-    $cell['data'] = l($cell['data'] . $image, current_path(), array('attributes' => array('title' => $title), 'query' => array_merge($ts['query'], array('sort' => $ts['sort'], 'order' => $cell['data'])), 'html' => TRUE));
-
-    unset($cell['field'], $cell['sort']);
-  }
-  return $cell;
-}
+    $cell_content = l($cell_content . $image, current_path(), array(
+      'attributes' => array('title' => $title),
+      'query' => array_merge($ts['query'], array(
+        'sort' => $ts['sort'],
+        'order' => $cell_content,
+      )),
+      'html' => TRUE,
+    ));
 
-/**
- * Formats a table cell.
- *
- * Adds a class attribute to all cells in the currently active column.
- *
- * @param $cell
- *   The cell to format.
- * @param $header
- *   An array of column headers in the format described in '#type' => 'table'.
- * @param $ts
- *   The current table sort context as returned from tablesort_init().
- * @param $i
- *   The index of the cell's table column.
- *
- * @return
- *   A properly formatted cell, ready for _theme_table_cell().
- */
-function tablesort_cell($cell, $header, $ts, $i) {
-  if (isset($header[$i]['data']) && $header[$i]['data'] == $ts['name'] && !empty($header[$i]['field'])) {
-    if (is_array($cell)) {
-      $cell['class'][] = 'active';
-    }
-    else {
-      $cell = array('data' => $cell, 'class' => array('active'));
-    }
+    unset($cell_attributes['field'], $cell_attributes['sort']);
   }
-  return $cell;
 }
 
 /**
diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index 52ce316..e657ce8 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -1547,20 +1547,45 @@ function theme_table($variables) {
     $i = 0;
     foreach ($header as $cell) {
       $i++;
-      // Track responsive classes for each column as needed. Only the header
-      // cells for a column are marked up with the responsive classes by a
-      // module developer or themer. The responsive classes on the header cells
-      // must be transferred to the content cells.
-      if (!empty($cell['class']) && is_array($cell['class'])) {
-        if (in_array(RESPONSIVE_PRIORITY_MEDIUM, $cell['class'])) {
-          $responsive[$i] =  RESPONSIVE_PRIORITY_MEDIUM;
+      if (!is_array($cell)) {
+        $cell_content = $cell;
+        $cell_attributes = '';
+        $is_header = TRUE;
+      }
+      else {
+        $cell_content = '';
+        if (isset($cell['data'])) {
+          $cell_content = $cell['data'];
+          unset($cell['data']);
+        }
+        // Flag the cell as a header or not and remove the flag.
+        $is_header = isset($cell['header']) ? $cell['header'] : TRUE;
+        unset($cell['header']);
+
+        // Track responsive classes for each column as needed. Only the header
+        // cells for a column are marked up with the responsive classes by a
+        // module developer or themer. The responsive classes on the header cells
+        // must be transferred to the content cells.
+        if (!empty($cell['class']) && is_array($cell['class'])) {
+          if (in_array(RESPONSIVE_PRIORITY_MEDIUM, $cell['class'])) {
+            $responsive[$i] = RESPONSIVE_PRIORITY_MEDIUM;
+          }
+          elseif (in_array(RESPONSIVE_PRIORITY_LOW, $cell['class'])) {
+            $responsive[$i] = RESPONSIVE_PRIORITY_LOW;
+          }
         }
-        elseif (in_array(RESPONSIVE_PRIORITY_LOW, $cell['class'])) {
-          $responsive[$i] =  RESPONSIVE_PRIORITY_LOW;
+
+        if (is_array($cell_content)) {
+          $cell_content = drupal_render($cell_content);
         }
+
+        tablesort_header($cell_content, $cell, $header, $ts);
+
+        // tablesort_header() removes the 'sort' and 'field' keys.
+        $cell_attributes = new Attribute($cell);
       }
-      $cell = tablesort_header($cell, $header, $ts);
-      $output .= _theme_table_cell($cell, TRUE);
+      $cell_tag = $is_header ? 'th' : 'td';
+      $output .= '<' . $cell_tag . $cell_attributes . '>' . $cell_content . '</' . $cell_tag . '>';
     }
     // Using ternary operator to close the tags based on whether or not there are rows
     $output .= (count($rows) ? " </tr></thead>\n" : "</tr>\n");
@@ -1602,19 +1627,39 @@ function theme_table($variables) {
         $i = 0;
         foreach ($cells as $cell) {
           $i++;
+          if (!is_array($cell)) {
+            $cell_content = $cell;
+            $cell_attributes = array();
+            $is_header = FALSE;
+          }
+          else {
+            $cell_content = '';
+            if (isset($cell['data'])) {
+              $cell_content = $cell['data'];
+              unset($cell['data']);
+            }
+            // Flag the cell as a header or not and remove the flag.
+            $is_header = !empty($cell['header']);
+            unset($cell['header']);
+
+            $cell_attributes = $cell;
+
+            if (is_array($cell_content)) {
+              $cell_content = drupal_render($cell_content);
+            }
+          }
           // Add active class if needed for sortable tables.
-          $cell = tablesort_cell($cell, $header, $ts, $i);
+          if (isset($header[$i]['data']) && $header[$i]['data'] == $ts['name'] && !empty($header[$i]['field'])) {
+            $cell_attributes['class'][] = 'active';
+          }
           // Copy RESPONSIVE_PRIORITY_LOW/RESPONSIVE_PRIORITY_MEDIUM
           // class from header to cell as needed.
           if (isset($responsive[$i])) {
-            if (is_array($cell)) {
-              $cell['class'][] = $responsive[$i];
-            }
-            else {
-              $cell = array('data' => $cell, 'class' => $responsive[$i]);
-            }
+            $cell_attributes['class'][] = $responsive[$i];
           }
-          $output .= _theme_table_cell($cell);
+
+          $cell_tag = $is_header ? 'th' : 'td';
+          $output .= '<' . $cell_tag . new Attribute($cell_attributes) . '>' . $cell_content . '</' . $cell_tag . '>';
         }
         $output .= " </tr>\n";
       }
@@ -1800,47 +1845,6 @@ function template_preprocess_container(&$variables) {
  */
 
 /**
- * Returns HTML output for a single table cell for theme_table().
- *
- * @param $cell
- *   Array of cell information, or string to display in cell.
- * @param bool $header
- *   TRUE if this cell is a table header cell, FALSE if it is an ordinary
- *   table cell. If $cell is an array with element 'header' set to TRUE, that
- *   will override the $header parameter.
- *
- * @return
- *   HTML for the cell.
- */
-function _theme_table_cell($cell, $header = FALSE) {
-  $attributes = '';
-
-  if (is_array($cell)) {
-    $data = isset($cell['data']) ? $cell['data'] : '';
-    // Cell's data property can be a string or a renderable array.
-    if (is_array($data)) {
-      $data = drupal_render($data);
-    }
-    $header |= isset($cell['header']);
-    unset($cell['data']);
-    unset($cell['header']);
-    $attributes = new Attribute($cell);
-  }
-  else {
-    $data = $cell;
-  }
-
-  if ($header) {
-    $output = "<th$attributes>$data</th>";
-  }
-  else {
-    $output = "<td$attributes>$data</td>";
-  }
-
-  return $output;
-}
-
-/**
  * Adds a default set of helper variables for preprocessors and templates.
  *
  * This function is called for theme hooks implemented as templates only, not
diff --git a/core/modules/system/lib/Drupal/system/Tests/Theme/TableTest.php b/core/modules/system/lib/Drupal/system/Tests/Theme/TableTest.php
index a5502e7..26a0fd8 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Theme/TableTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Theme/TableTest.php
@@ -7,16 +7,24 @@
 
 namespace Drupal\system\Tests\Theme;
 
-use Drupal\simpletest\WebTestBase;
+use Drupal\simpletest\DrupalUnitTestBase;
 
 /**
  * Unit tests for theme_table().
  */
-class TableTest extends WebTestBase {
+class TableTest extends DrupalUnitTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('system');
+
   public static function getInfo() {
     return array(
       'name' => 'Theme Table',
-      'description' => 'Tests built-in theme functions.',
+      'description' => 'Tests built-in table theme functions.',
       'group' => 'Theme',
     );
   }
@@ -106,4 +114,58 @@ function testThemeTableWithNoStriping() {
     $this->assertNoRaw('class="odd"', 'Odd/even classes were not added because $no_striping = TRUE.');
     $this->assertNoRaw('no_striping', 'No invalid no_striping HTML attribute was printed.');
   }
+
+  /**
+   * Tests that the 'header' option in cells works correctly.
+   */
+  function testThemeTableHeaderCellOption() {
+    $rows = array(
+      array(
+        array('data' => 1, 'header' => TRUE),
+        array('data' => 1, 'header' => FALSE),
+        array('data' => 1),
+      ),
+    );
+    $table = array(
+      '#type' => 'table',
+      '#rows' => $rows,
+    );
+    $this->content = drupal_render($table);
+    $this->assertRaw('<th>1</th><td>1</td><td>1</td>', 'The th and td tags was printed correctly.');
+  }
+
+  /**
+   * Asserts that a raw string appears in $this->content.
+   *
+   * @param string $value
+   *   The expected string.
+   * @param string $message
+   *   (optional) A custom assertion message.
+   */
+  protected function assertRaw($value, $message = NULL) {
+    if (!isset($message)) {
+      $message = String::format("Raw value @value found.", array(
+        '@value' => var_export($value, TRUE),
+      ));
+    }
+    $this->assert(strpos($this->content, $value) !== FALSE, $message);
+  }
+
+  /**
+   * Asserts that a raw string does not appear in $this->content.
+   *
+   * @param string $value
+   *   The not expected string.
+   * @param string $message
+   *   (optional) A custom assertion message.
+   */
+  protected function assertNoRaw($value, $message = NULL) {
+    if (!isset($message)) {
+      $message = String::format("Raw value @value not found.", array(
+        '@value' => var_export($value, TRUE),
+      ));
+    }
+    $this->assert(strpos($this->content, $value) === FALSE, $message);
+  }
+
 }
