diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index 4230087..8e423b6 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -1460,6 +1460,13 @@ function drupal_pre_render_table(array $element) {
  *       )
  *     );
  *     @endcode
+ *   - footer: An array containing the table footers. Each element of the array
+ *     can be either a localized string or an associative array with the
+ *     following keys:
+ *     - "data": The localized summary information of the table column.
+ *     - "header": Indicates this cell is a header.
+ *     - Any HTML attributes, such as "colspan", to apply to the column footer
+ *       cell.
  *   - attributes: An array of HTML attributes to apply to the table tag.
  *   - caption: A localized string to use for the <caption> tag.
  *   - colgroups: An array of column groups. Each element of the array can be
@@ -1598,6 +1605,50 @@ function template_preprocess_table(&$variables) {
     }
   }
 
+  // Format the table footer:
+  if (!empty($variables['footer'])) {
+
+    foreach ($variables['footer'] as $col_key => $cell) {
+      if (!is_array($cell)) {
+        $cell_content = $cell;
+        $cell_attributes = new Attribute();
+        $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 = isset($cell['header']) ? $cell['header'] : FALSE;
+        unset($cell['header']);
+
+        // Track responsive classes for each column as needed. Only the footer
+        // cells for a column are marked up with the responsive classes by a
+        // module developer or themer. The responsive classes on the footer 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_classes[$col_key] = RESPONSIVE_PRIORITY_MEDIUM;
+          }
+          elseif (in_array(RESPONSIVE_PRIORITY_LOW, $cell['class'])) {
+            $responsive_classes[$col_key] = RESPONSIVE_PRIORITY_LOW;
+          }
+        }
+
+        if (is_array($cell_content)) {
+          $cell_content = drupal_render($cell_content);
+        }
+        $cell_attributes = new Attribute($cell);
+      }
+      $variables['footer'][$col_key] = array();
+      $variables['footer'][$col_key]['tag'] = $is_header ? 'th' : 'td';
+      $variables['footer'][$col_key]['attributes'] = $cell_attributes;
+      $variables['footer'][$col_key]['content'] = $cell_content;
+    }
+  }
+
   if (!empty($variables['rows'])) {
     $flip = array('even' => 'odd', 'odd' => 'even');
     $class = 'even';
@@ -2553,7 +2604,7 @@ function drupal_common_theme() {
       'template' => 'breadcrumb',
     ),
     'table' => array(
-      'variables' => array('header' => NULL, 'rows' => NULL, 'attributes' => array(), 'caption' => NULL, 'colgroups' => array(), 'sticky' => FALSE, 'responsive' => TRUE, 'empty' => ''),
+      'variables' => array('header' => NULL, 'footer' => NULL, 'rows' => NULL, 'attributes' => array(), 'caption' => NULL, 'colgroups' => array(), 'sticky' => FALSE, 'responsive' => TRUE, 'empty' => ''),
       'template' => 'table',
     ),
     'tablesort_indicator' => array(
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 6b9c5ef..5f1b609 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Theme/TableTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Theme/TableTest.php
@@ -86,15 +86,27 @@ function testThemeTableWithEmptyMessage() {
         'colspan' => 2,
       ),
     );
+    $footer = array(
+      array(
+        'data' => 'Footer 1',
+        'header' => TRUE,
+      ),
+      array(
+        'data' => 'Footer 2',
+        'colspan' => 2,
+      ),
+    );
     $table = array(
       '#type' => 'table',
       '#header' => $header,
+      '#footer' => $footer,
       '#rows' => array(),
       '#empty' => 'Empty row.',
     );
     $this->render($table);
     $this->removeWhiteSpace();
     $this->assertRaw('<thead><tr><th>Header 1</th><th colspan="2">Header 2</th></tr>', 'Table header found.');
+    $this->assertRaw('<tfoot><tr><th>Footer 1</th><td colspan="2">Footer 2</td></tr>', 'Table footer found.');
     $this->assertRaw('<tr class="odd"><td colspan="3" class="empty message">Empty row.</td>', 'Colspan on #empty row found.');
   }
 
diff --git a/core/modules/system/templates/table.html.twig b/core/modules/system/templates/table.html.twig
index ce69286..884349a 100644
--- a/core/modules/system/templates/table.html.twig
+++ b/core/modules/system/templates/table.html.twig
@@ -28,6 +28,11 @@
  *     - attributes: Any HTML attributes, such as "colspan", to apply to the
  *       table cell.
  *     - content: The string to display in the table cell.
+ * - footer: Table footer cells. Each cell contains the following properties:
+ *   - tag: The HTML tag name to use; either TH or TD.
+ *   - attributes: HTML attributes to apply to the tag.
+ *   - content: A localized string for the title of the column.
+ *   - field: Field name (required for column sorting).
  * - empty: The message to display in an extra row if table does not have
  *   any rows.
  *
@@ -40,7 +45,6 @@
   {% if caption %}
     <caption>{{ caption }}</caption>
   {% endif %}
-
   {% for colgroup in colgroups %}
     {% if colgroup.cols %}
       <colgroup{{ colgroup.attributes }}>
@@ -52,7 +56,6 @@
       <colgroup{{ colgroup.attributes }} />
     {% endif %}
   {% endfor %}
-
   {% if header %}
     <thead>
       <tr>
@@ -64,7 +67,6 @@
       </tr>
     </thead>
   {% endif %}
-
   {% if rows %}
     <tbody>
       {% for row in rows %}
@@ -78,4 +80,15 @@
       {% endfor %}
     </tbody>
   {% endif %}
+  {% if footer %}
+    <tfoot>
+      <tr>
+        {% for cell in footer %}
+          <{{ cell.tag }}{{ cell.attributes }}>
+            {{- cell.content -}}
+          </{{ cell.tag }}>
+        {% endfor %}
+      </tr>
+    </tfoot>
+  {% endif %}
 </table>
