diff --git a/core/includes/tablesort.inc b/core/includes/tablesort.inc
index c42b1f4..3a6e920 100644
--- a/core/includes/tablesort.inc
+++ b/core/includes/tablesort.inc
@@ -36,7 +36,7 @@ function tablesort_init($header) {
  *   The current table sort context as returned from tablesort_init().
  *
  * @return
- *   A properly formatted cell, ready for _theme_table_cell().
+ *   A properly formatted cell.
  */
 function tablesort_header($cell, $header, $ts) {
   // Special formatting for the currently sorted column header.
@@ -78,7 +78,7 @@ function tablesort_header($cell, $header, $ts) {
  *   The index of the cell's table column.
  *
  * @return
- *   A properly formatted cell, ready for _theme_table_cell().
+ *   A properly formatted cell.
  */
 function tablesort_cell($cell, $header, $ts, $i) {
   if (isset($header[$i]['data']) && $header[$i]['data'] == $ts['name'] && !empty($header[$i]['field'])) {
diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index a38dbe0..98f30a7 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -2186,20 +2186,37 @@ 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 = array('data' => $cell, 'attributes' => new Attribute());
+      }
+      else {
+        if (!isset($cell['data'])) {
+          $cell['data'] = '';
         }
-        elseif (in_array(RESPONSIVE_PRIORITY_LOW, $cell['class'])) {
-          $responsive[$i] =  RESPONSIVE_PRIORITY_LOW;
+        // 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;
+          }
         }
+        $cell = tablesort_header($cell, $header, $ts);
+        // @todo Refactor this so that attributes are not top-level.
+        $_cell = $cell;
+        unset($_cell['data']);
+        unset($_cell['header']);
+        $cell['attributes'] = new Attribute($_cell);
       }
-      $cell = tablesort_header($cell, $header, $ts);
-      $output .= _theme_table_cell($cell, TRUE);
+
+      $output .= '<th' . $cell['attributes'] . '>';
+      $output .= is_array($cell['data']) ? drupal_render($cell['data']) : $cell['data'];
+      $output .= '</th>';
     }
     // Using ternary operator to close the tags based on whether or not there are rows
     $output .= (count($rows) ? " </tr></thead>\n" : "</tr>\n");
@@ -2242,19 +2259,36 @@ function theme_table($variables) {
         $i = 0;
         foreach ($cells as $cell) {
           $i++;
-          // Add active class if needed for sortable tables.
-          $cell = tablesort_cell($cell, $header, $ts, $i);
-          // 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];
+
+          if (!is_array($cell)) {
+            $cell = array('data' => $cell, 'attributes' => new Attribute(array('class' => array())));
+            // Add responsive class.
+            if (isset($responsive[$i])) {
+              $cell['attributes']['class'][] = $responsive[$i];
             }
-            else {
-              $cell = array('data' => $cell, 'class' => $responsive[$i]);
+          }
+          else {
+            if (!isset($cell['data'])) {
+              $cell['data'] = '';
+            }
+            $cell = tablesort_cell($cell, $header, $ts, $i);
+            // @todo Refactor this so that attributes are not top-level.
+            $_cell = $cell;
+            unset($_cell['data']);
+            unset($_cell['header']);
+            $cell['attributes'] = new Attribute($_cell);
+            // Add responsive class.
+            if (isset($responsive[$i])) {
+              if (!is_array($cell['attributes']['class'])) {
+                $cell['attributes']['class'] = array();
+              }
+              $cell['attributes']['class'][] = $responsive[$i];
             }
           }
-          $output .= _theme_table_cell($cell);
+
+          $output .= '<td' . $cell['attributes'] . '>';
+          $output .= is_array($cell['data']) ? drupal_render($cell['data']) : $cell['data'];
+          $output .= '</td>';
         }
         $output .= " </tr>\n";
       }
@@ -2571,47 +2605,6 @@ function theme_indentation($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 variable processors and templates.
  *
  * This function is called for theme hooks implemented as templates only, not
diff --git a/core/modules/forum/forum.module b/core/modules/forum/forum.module
index ce8397d..a38246d 100644
--- a/core/modules/forum/forum.module
+++ b/core/modules/forum/forum.module
@@ -6,6 +6,7 @@
  */
 
 use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Template\Attribute;
 use Drupal\node\Plugin\Core\Entity\Node;
 use Drupal\entity\Plugin\Core\Entity\EntityDisplay;
 use Drupal\taxonomy\Plugin\Core\Entity\Term;
@@ -1124,7 +1125,12 @@ function template_preprocess_forum_topic_list(&$variables) {
   $header = '';
   foreach ($forum_topic_list_header as $cell) {
     $cell = tablesort_header($cell, $forum_topic_list_header, $ts);
-    $header .= _theme_table_cell($cell, TRUE);
+    // @todo Refactor this so that attributes are not top-level.
+    // @see theme_table
+    $_cell = $cell;
+    unset($_cell['data']);
+    $cell['attributes'] = new Attribute($_cell);
+    $header .= "<th" . $cell['attributes'] . ">" . drupal_render($cell['data']) . "</th>";
   }
   $variables['header'] = $header;
 
