diff --git a/core/includes/form.inc b/core/includes/form.inc
index 9190e31..9302d73 100644
--- a/core/includes/form.inc
+++ b/core/includes/form.inc
@@ -38,7 +38,6 @@ function template_preprocess_select(&$variables) {
   Element\RenderElement::setAttributes($element, array('form-select'));
 
   $variables['attributes'] = $element['#attributes'];
-  $variables['options'] = form_select_options($element);
 }
 
 /**
diff --git a/core/modules/system/templates/select.html.twig b/core/modules/system/templates/select.html.twig
index 21f32ac..3235c95 100644
--- a/core/modules/system/templates/select.html.twig
+++ b/core/modules/system/templates/select.html.twig
@@ -12,4 +12,55 @@
  * @ingroup themeable
  */
 #}
-<select{{ attributes }}>{{ options }}</select>
+{% import _self as options %}
+<select{{ attributes }}>
+  {% if element['#options'] is not empty %}
+    {{ options.build(element) }}
+  {% endif %}
+</select>
+
+{% macro build(element, choices) %}
+  {% import _self as options %}
+  {% if choices is empty %}
+    {% set choices = element['#options'] %}
+  {% endif %}
+
+  {# The defined test accommodates cases where element['#value'] is null. #}
+  {#% set value_valid = element['#value'] is defined %#}
+  {#% set value_is_array = value_valid and element['#value'] is iterable %#}
+
+  {# Check if the element is multiple select and no value has been selected. #}
+  {% set empty_value = element['#value'] is empty and element['#multiple'] is not empty %}
+
+  {% for key, choice in choices %}
+    {#
+      If 'choice' is an iterable object and also has an option property, the
+      object will be iterated rather than accessing the option property.
+    #}
+    {% if choice is iterable %}
+      <optgroup label="{{ key }}">
+        {{ options.build(element, choice) }}
+      </optgroup>
+    {# Handle object properties. #}
+    {% elseif choice.option %}
+      {{ options.build(element, choice.option) }}
+    {% else %}
+      {% spaceless %}
+        {# Cast key to a string. #}
+        {% set key = "#{key}" %}
+        {# The defined test accommodates cases where element['#value'] is null. #}
+        {% set empty_choice = element['#value'] is empty and element['#multiple'] is not empty %}
+        {% if element['#value'] is not defined %}
+          {% set selected = false %}
+        {% elseif element['#value'] is not iterable %}
+          {% set selected = ("#{element['#value']}" is same as(key)) %}
+        {% elseif key in element['#value'] %}
+          {% set selected = true %}
+        {% elseif empty_choice and key == '_none' %}
+          {% set selected = true %}
+        {% endif %}
+        <option value="{{ key }}"{{ selected ? ' selected="selected"' : '' }}>{{ choice }}</option>
+      {% endspaceless %}
+    {% endif %}
+  {% endfor %}
+{% endmacro %}
diff --git a/core/themes/classy/templates/form/select.html.twig b/core/themes/classy/templates/form/select.html.twig
deleted file mode 100644
index 51baa7a..0000000
--- a/core/themes/classy/templates/form/select.html.twig
+++ /dev/null
@@ -1,13 +0,0 @@
-{#
-/**
- * @file
- * Theme override for a select element.
- *
- * Available variables:
- * - attributes: HTML attributes for the select tag.
- * - options: The option element children.
- *
- * @see template_preprocess_select()
- */
-#}
-<select{{ attributes }}>{{ options }}</select>
