diff --git a/core/lib/Drupal/Core/Render/Element/MoreLink.php b/core/lib/Drupal/Core/Render/Element/MoreLink.php
index 4f7e90c..6551abb 100644
--- a/core/lib/Drupal/Core/Render/Element/MoreLink.php
+++ b/core/lib/Drupal/Core/Render/Element/MoreLink.php
@@ -24,7 +24,7 @@ public function getInfo() {
       '#title' => $this->t('More'),
       '#theme_wrappers' => array(
         'container' => array(
-          '#attributes' => array('class' => 'more-link'),
+          '#attributes' => array('class' => array('more-link')),
         ),
       ),
     ) + $info;
diff --git a/core/lib/Drupal/Core/Render/Element/SystemCompactLink.php b/core/lib/Drupal/Core/Render/Element/SystemCompactLink.php
new file mode 100644
index 0000000..501dc4b
--- /dev/null
+++ b/core/lib/Drupal/Core/Render/Element/SystemCompactLink.php
@@ -0,0 +1,77 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Render\Element\SystemCompactLink.
+ */
+
+namespace Drupal\Core\Render\Element;
+
+/**
+ * Provides a link render element.
+ *
+ * @RenderElement("system_compact_link")
+ */
+class SystemCompactLink extends Link {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getInfo() {
+    $class = get_class($this);
+    return array(
+      '#pre_render' => array(
+        array($class, 'preRenderCompactLink'),
+        array($class, 'preRenderLink'),
+      ),
+      '#theme_wrappers' => array(
+        'container' => array(
+          '#attributes' => array('class' => array('compact-link')),
+        ),
+      ),
+    );
+  }
+
+  /**
+   * Pre-render callback: Renders a link into #markup.
+   *
+   * Doing so during pre_render gives modules a chance to alter the link parts.
+   *
+   * @param array $element
+   *   A structured array whose keys form the arguments to l():
+   *   - #title: The link text to pass as argument to l().
+   *   - One of the following:
+   *     - #route_name and (optionally) a #route_parameters array; The route
+   *       name and route parameters which will be passed into the link
+   *       generator.
+   *     - #href: The system path or URL to pass as argument to l().
+   *   - #options: (optional) An array of options to pass to l() or the link
+   *     generator.
+   *
+   * @return array
+   *   The passed-in element containing the system compact link default values.
+   */
+  public static function preRenderCompactLink($element) {
+    // By default, link options to pass to l() are normally set in #options.
+    $element += array('#options' => array());
+
+    if (system_admin_compact_mode()) {
+      $element['#title'] = t('Show descriptions');
+      $element['#href'] = 'admin/compact/off';
+      $element['#options'] = array(
+        'attributes' => array('title' => t('Expand layout to include descriptions.')),
+        'query' => drupal_get_destination(),
+      );
+    }
+    else {
+      $element['#title'] = t('Hide descriptions');
+      $element['#href'] = 'admin/compact/on';
+      $element['#options'] = array(
+        'attributes' => array('title' => t('Compress layout by hiding descriptions.')),
+        'query' => drupal_get_destination(),
+      );
+    }
+    return $element;
+  }
+
+}
diff --git a/core/modules/system/css/system.admin.css b/core/modules/system/css/system.admin.css
index 853ded2..2c1269b 100644
--- a/core/modules/system/css/system.admin.css
+++ b/core/modules/system/css/system.admin.css
@@ -28,7 +28,7 @@ div.admin .expert-link {
 }
 
 /**
- * Markup generated by theme_system_compact_link().
+ * System compact link: to toggle the display of description text.
  */
 .compact-link {
   margin: 0 0 0.5em 0;
diff --git a/core/modules/system/src/Tests/Common/RenderElementTypesTest.php b/core/modules/system/src/Tests/Common/RenderElementTypesTest.php
index 6d83838..bffb4e6 100644
--- a/core/modules/system/src/Tests/Common/RenderElementTypesTest.php
+++ b/core/modules/system/src/Tests/Common/RenderElementTypesTest.php
@@ -184,4 +184,50 @@ function testMoreLink() {
     }
   }
 
+  /**
+   * Tests system #type 'system_compact_link'.
+   */
+  function testSystemCompactLink() {
+    $elements = array(
+      array(
+        'name' => "#type 'system_compact_link' when admin compact mode is off",
+        'value' => array(
+          '#type' => 'system_compact_link',
+        ),
+        'expected' => '//div[@class="compact-link"]/a[contains(@href, "admin/compact/on") and text()="Hide descriptions"]',
+      ),
+      array(
+        'name' => "#type 'system_compact_link' when adding extra attributes",
+        'value' => array(
+          '#type' => 'system_compact_link',
+          '#attributes' => array(
+            'class' => array('kittens-rule'),
+          ),
+        ),
+        'expected' => '//div[@class="compact-link"]/a[contains(@href, "admin/compact/on") and @class="kittens-rule" and text()="Hide descriptions"]',
+      ),
+    );
+
+    foreach ($elements as $element) {
+      $xml = new \SimpleXMLElement(drupal_render($element['value']));
+      $result = $xml->xpath($element['expected']);
+      $this->assertTrue($result, '"' . $element['name'] . '" is rendered correctly by drupal_render().');
+    }
+
+    // Set admin compact mode on for additional tests.
+    \Drupal::request()->cookies->set('Drupal_visitor_admin_compact_mode', TRUE);
+
+    $element = array(
+      'name' => "#type 'system_compact_link' when admin compact mode is on",
+      'value' => array(
+        '#type' => 'system_compact_link',
+      ),
+      'expected' => '//div[@class="compact-link"]/a[contains(@href, "admin/compact/off") and text()="Show descriptions"]',
+    );
+
+    $xml = new \SimpleXMLElement(drupal_render($element['value']));
+    $result = $xml->xpath($element['expected']);
+    $this->assertTrue($result, '"' . $element['name'] . '" is rendered correctly by drupal_render().');
+  }
+
 }
diff --git a/core/modules/system/system.admin.inc b/core/modules/system/system.admin.inc
index 57edc26..0fc5922 100644
--- a/core/modules/system/system.admin.inc
+++ b/core/modules/system/system.admin.inc
@@ -84,7 +84,7 @@ function template_preprocess_admin_block_content(&$variables) {
  */
 function template_preprocess_admin_page(&$variables) {
   $variables['system_compact_link'] = array(
-    '#theme' => 'system_compact_link',
+    '#type' => 'system_compact_link',
   );
   $variables['containers'] = array();
   $stripe = 0;
@@ -113,7 +113,7 @@ function template_preprocess_admin_page(&$variables) {
  */
 function template_preprocess_system_admin_index(&$variables) {
   $variables['system_compact_link'] = array(
-    '#theme' => 'system_compact_link',
+    '#type' => 'system_compact_link',
   );
   $variables['containers'] = array();
   $stripe = 0;
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index b478fb4..400762e 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -217,9 +217,6 @@ function system_theme() {
       'file' => 'system.admin.inc',
       'template' => 'system-admin-index',
     ),
-    'system_compact_link' => array(
-      'variables' => array(),
-    ),
   ));
 }
 
@@ -1163,24 +1160,6 @@ function system_time_zones($blank = NULL) {
 }
 
 /**
- * Returns HTML for a link to show or hide inline help descriptions.
- *
- * @ingroup themeable
- */
-function theme_system_compact_link() {
-  $output = '<div class="compact-link">';
-  if (system_admin_compact_mode()) {
-    $output .= \Drupal::l(t('Show descriptions'), 'system.admin_compact_page', array('mode' => 'off'), array('attributes' => array('title' => t('Expand layout to include descriptions.')), 'query' => drupal_get_destination()));
-  }
-  else {
-    $output .= \Drupal::l(t('Hide descriptions'), 'system.admin_compact_page', array('mode' => 'on'), array('attributes' => array('title' => t('Compress layout by hiding descriptions.')), 'query' => drupal_get_destination()));
-  }
-  $output .= '</div>';
-
-  return $output;
-}
-
-/**
  * Attempts to get a file using Guzzle HTTP client and to store it locally.
  *
  * @param string $url
diff --git a/core/modules/user/src/Form/UserPermissionsForm.php b/core/modules/user/src/Form/UserPermissionsForm.php
index 3f89bb6..b3e4d80 100644
--- a/core/modules/user/src/Form/UserPermissionsForm.php
+++ b/core/modules/user/src/Form/UserPermissionsForm.php
@@ -96,8 +96,9 @@ public function buildForm(array $form, FormStateInterface $form_state) {
     $module_info = system_rebuild_module_data();
     $hide_descriptions = system_admin_compact_mode();
 
+    $system_compact_link = array('#type' => 'system_compact_link');
     $form['system_compact_link'] = array(
-      '#theme' => 'system_compact_link',
+      '#markup' => drupal_render($system_compact_link),
     );
 
     $form['permissions'] = array(
