diff --git a/core/includes/form.inc b/core/includes/form.inc
index ce5779c..820f146 100644
--- a/core/includes/form.inc
+++ b/core/includes/form.inc
@@ -2767,8 +2767,12 @@ function template_preprocess_form_element(&$variables) {
   if (!empty($element['#attributes']['disabled'])) {
     $variables['attributes']['class'][] = 'form-disabled';
   }
+  // Add a class for required elements.
+  if (!empty($element['#required'])) {
+    $variables['attributes']['class'][] = 'form-required';
+  }
 
-  // If #title is not set, we don't display any label or required marker.
+  // If #title is not set, we don't display any label.
   if (!isset($element['#title'])) {
     $element['#title_display'] = 'none';
   }
@@ -2794,23 +2798,6 @@ function template_preprocess_form_element(&$variables) {
 }
 
 /**
- * Returns HTML for a marker for required form elements.
- *
- * @param $variables
- *   An associative array containing:
- *   - element: An associative array containing the properties of the element.
- *
- * @ingroup themeable
- */
-function theme_form_required_marker($variables) {
-  $attributes = array(
-    'class' => 'form-required',
-    'aria-hidden' => 'true',
-  );
-  return '<span' . new Attribute($attributes) . '>*</span>';
-}
-
-/**
  * Returns HTML for a form element label and required marker.
  *
  * Form element labels include the #title and a #required marker. The label is
@@ -2840,16 +2827,6 @@ function theme_form_element_label($variables) {
     return '';
   }
 
-  // If the element is required, a required marker is appended to the label.
-  $required = '';
-  if (!empty($element['#required'])) {
-    $marker = array(
-      '#theme' => 'form_required_marker',
-      '#element' => $element,
-    );
-    $required = drupal_render($marker);
-  }
-
   $title = filter_xss_admin($element['#title']);
 
   $attributes = array();
@@ -2866,7 +2843,7 @@ function theme_form_element_label($variables) {
     $attributes['for'] = $element['#id'];
   }
 
-  return '<label' . new Attribute($attributes) . '>' . t('!title!required', array('!title' => $title, '!required' => $required)) . '</label>';
+  return '<label' . new Attribute($attributes) . '>' . t('!title', array('!title' => $title)) . '</label>';
 }
 
 /**
diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index f98aadd..0ab996d 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -1898,6 +1898,10 @@ function theme_container($variables) {
     if (!isset($element['#attributes']['id'])) {
       $element['#attributes']['id'] = $element['#id'];
     }
+    // Add a class for required elements.
+    if (!empty($element['widget']['#required'])) {
+      $element['#attributes']['class'][] = 'form-required';
+    }
     // Add the 'form-wrapper' class.
     $element['#attributes']['class'][] = 'form-wrapper';
   }
@@ -2700,9 +2704,6 @@ function drupal_common_theme() {
       'render element' => 'element',
       'template' => 'form-element',
     ),
-    'form_required_marker' => array(
-      'render element' => 'element',
-    ),
     'form_element_label' => array(
       'render element' => 'element',
     ),
diff --git a/core/misc/states.js b/core/misc/states.js
index abdfbf8..4e57f95 100644
--- a/core/misc/states.js
+++ b/core/misc/states.js
@@ -517,14 +517,14 @@
   $(document).on('state:required', function (e) {
     if (e.trigger) {
       if (e.value) {
-        var $label = $(e.target).attr({ 'required': 'required', 'aria-required': 'aria-required' }).closest('.form-item, .form-wrapper').find('label');
+        var $formWrapper = $(e.target).attr({ 'required': 'required', 'aria-required': 'aria-required' }).closest('.form-item, .form-wrapper');
         // Avoids duplicate required markers on initialization.
-        if (!$label.find('.form-required').length) {
-          $label.append(Drupal.theme('requiredMarker'));
+        if (!$formWrapper.hasClass('form-required').length) {
+          $formWrapper.addClass('form-required');
         }
       }
       else {
-        $(e.target).removeAttr('required aria-required').closest('.form-item, .form-wrapper').find('label .form-required').remove();
+        $(e.target).removeAttr('required aria-required').closest('.form-item.form-required, .form-wrapper.form-required').removeClass('form-required');
       }
     }
   });
@@ -570,10 +570,4 @@
     return (a === b) ? (typeof a === 'undefined' ? a : true) : (typeof a === 'undefined' || typeof b === 'undefined');
   }
 
-  $.extend(Drupal.theme, {
-    requiredMarker: function () {
-      return '<abbr class="form-required" title="' + Drupal.t('This field is required.') + '">*</abbr>';
-    }
-  });
-
 })(jQuery);
diff --git a/core/modules/datetime/datetime.module b/core/modules/datetime/datetime.module
index ccf1a0c..8828f85 100644
--- a/core/modules/datetime/datetime.module
+++ b/core/modules/datetime/datetime.module
@@ -224,16 +224,6 @@ function template_preprocess_datetime_form(&$variables) {
  */
 function template_preprocess_datetime_wrapper(&$variables) {
   $element = $variables['element'];
-
-  // If the element is required, a required marker is appended to the label.
-  $variables['required'] = NULL;
-  if(!empty($element['#required'])) {
-    $variables['required'] = array(
-      '#theme' => 'form_required_marker',
-      '#element' => $element,
-    );
-  }
-
   if (!empty($element['#title'])) {
     $variables['title'] = $element['#title'];
   }
diff --git a/core/modules/datetime/templates/datetime-wrapper.html.twig b/core/modules/datetime/templates/datetime-wrapper.html.twig
index a4acf70..cb73680 100644
--- a/core/modules/datetime/templates/datetime-wrapper.html.twig
+++ b/core/modules/datetime/templates/datetime-wrapper.html.twig
@@ -7,7 +7,6 @@
  * - content: The form element to be output, usually a datelist, or datetime.
  * - title: The title of the form element.
  * - attributes: HTML attributes for the form wrapper.
- * - required: (optional) A marker indicating that the form element is required.
  * - description: Description text for the form element.
  *
  * @see template_preprocess_datetime_wrapper()
@@ -16,9 +15,7 @@
  */
 #}
 {% if title %}
-  <h4 class="label">
-    {% trans %}{{ title|passthrough }}{{ required|passthrough }}{% endtrans %}
-  </h4>
+  <h4 class="label">{{ title }}</h4>
 {% endif %}
 {{ content }}
 {% if description %}
diff --git a/core/modules/field/field.form.inc b/core/modules/field/field.form.inc
index c7c2e05..389b760 100644
--- a/core/modules/field/field.form.inc
+++ b/core/modules/field/field.form.inc
@@ -26,14 +26,12 @@ function theme_field_multiple_value_form($variables) {
   $output = '';
 
   if ($element['#cardinality_multiple']) {
-    $form_required_marker = array('#theme' => 'form_required_marker');
-    $required = !empty($element['#required']) ? drupal_render($form_required_marker) : '';
     $table_id = drupal_html_id($element['#field_name'] . '_values');
     $order_class = $element['#field_name'] . '-delta-order';
 
     $header = array(
       array(
-        'data' => '<h4 class="label">' . t('!title !required', array('!title' => $element['#title'], '!required' => $required)) . "</h4>",
+        'data' => '<h4 class="label">' . t('!title', array('!title' => $element['#title'])) . "</h4>",
         'colspan' => 2,
         'class' => array('field-label'),
       ),
diff --git a/core/modules/system/css/system.theme.css b/core/modules/system/css/system.theme.css
index f205034..1cbe70b 100644
--- a/core/modules/system/css/system.theme.css
+++ b/core/modules/system/css/system.theme.css
@@ -77,13 +77,23 @@ h4.label {
 .form-type-checkbox .description {
   margin-left: 2.4em;
 }
-.marker,
-.form-required {
+.marker {
   color: #e00;
 }
-abbr.form-required, abbr.tabledrag-changed, abbr.ajax-changed {
+.form-required label:not(.option):after,
+.form-required .label:after {
+  content: "*";
+  speak: none;
+  color: #e00;
+}
+/*
+Not sure how to deal with this...
+abbr.form-required, */
+abbr.tabledrag-changed,
+abbr.ajax-changed {
   border-bottom: none;
 }
+
 .form-item input.error,
 .form-item textarea.error,
 .form-item select.error {
diff --git a/core/modules/system/lib/Drupal/system/Tests/Form/ElementsLabelsTest.php b/core/modules/system/lib/Drupal/system/Tests/Form/ElementsLabelsTest.php
index 6c51a04..29825a4 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Form/ElementsLabelsTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Form/ElementsLabelsTest.php
@@ -59,10 +59,10 @@ function testFormLabels() {
 
     // Exercise various defaults for textboxes and modifications to ensure
     // appropriate override and correct behavior.
-    $elements = $this->xpath('//label[@for="edit-form-textfield-test-title-and-required"]/child::span[@class="form-required"]/parent::*/following-sibling::input[@id="edit-form-textfield-test-title-and-required"]');
+    $elements = $this->xpath('//label[@for="edit-form-textfield-test-title-and-required"]/parent::div[contains(@class, "form-required")]/input[@id="edit-form-textfield-test-title-and-required"]');
     $this->assertTrue(isset($elements[0]), 'Label precedes textfield, with required marker inside label.');
 
-    $elements = $this->xpath('//input[@id="edit-form-textfield-test-no-title-required"]/preceding-sibling::label[@for="edit-form-textfield-test-no-title-required"]/span[@class="form-required"]');
+    $elements = $this->xpath('//input[@id="edit-form-textfield-test-no-title-required"]/preceding-sibling::label[@for="edit-form-textfield-test-no-title-required"]/parent::div[contains(@class, "form-required")]');
     $this->assertTrue(isset($elements[0]), 'Label tag with required marker precedes required textfield with no title.');
 
     $elements = $this->xpath('//input[@id="edit-form-textfield-test-title-invisible"]/preceding-sibling::label[@for="edit-form-textfield-test-title-invisible" and @class="visually-hidden"]');
diff --git a/core/modules/system/lib/Drupal/system/Tests/Form/FormTest.php b/core/modules/system/lib/Drupal/system/Tests/Form/FormTest.php
index 5424f66..fc4e0ed 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Form/FormTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Form/FormTest.php
@@ -94,8 +94,8 @@ function testRequiredFields() {
     $elements['file']['empty_values'] = $empty_strings;
 
     // Regular expression to find the expected marker on required elements.
-    $required_marker_preg = '@<label.*<span class="form-required" aria-hidden="true">\*</span></label>@';
-
+    // @todo look for class on container element.
+    $required_marker_preg = '@<div class=".*?form-required.*?">@';
     // Go through all the elements and all the empty values for them.
     foreach ($elements as $type => $data) {
       foreach ($data['empty_values'] as $key => $empty) {
diff --git a/core/modules/system/templates/form-required-marker.html.twig b/core/modules/system/templates/form-required-marker.html.twig
new file mode 100644
index 0000000..8e28020
--- /dev/null
+++ b/core/modules/system/templates/form-required-marker.html.twig
@@ -0,0 +1,12 @@
+{#
+/**
+ * @file
+ * Default theme implementation for a form element required marker.
+ *
+ * Available variables:
+ * - attributes: A list of HTML attributes for the marker.
+ *
+ * @ingroup themeable
+ */
+#}
+<span class="form-required" aria-hidden="true">*</span>
diff --git a/core/themes/bartik/css/style.css b/core/themes/bartik/css/style.css
index 85c834a..709b6dc 100644
--- a/core/themes/bartik/css/style.css
+++ b/core/themes/bartik/css/style.css
@@ -421,7 +421,8 @@ h1#site-name {
   background: #fff;
   background: rgba(255, 255, 255, 0.8);
 }
-.region-header .form-required {
+.region-header .form-required label:not(.option):after,
+.region-header .form-required .label:after {
   color: #eee;
   color: rgba(255, 255, 255, 0.7);
 }
