diff --git a/core/core.libraries.yml b/core/core.libraries.yml
index 6ccf72bbdf..83b423f2bf 100644
--- a/core/core.libraries.yml
+++ b/core/core.libraries.yml
@@ -706,17 +706,6 @@ drupal.tabledrag.ajax:
     - core/ajax
     - core/tabledrag
 
-drupal.tableheader:
-  version: VERSION
-  js:
-    misc/tableheader.js: {}
-  dependencies:
-    - core/jquery
-    - core/drupal
-    - core/drupalSettings
-    - core/once
-    - core/drupal.displace
-
 drupal.tableresponsive:
   version: VERSION
   js:
diff --git a/core/lib/Drupal/Core/Render/Element/Table.php b/core/lib/Drupal/Core/Render/Element/Table.php
index f55572e5f2..ed78da44a1 100644
--- a/core/lib/Drupal/Core/Render/Element/Table.php
+++ b/core/lib/Drupal/Core/Render/Element/Table.php
@@ -22,8 +22,8 @@
  * - #empty: Text to display when no rows are present.
  * - #responsive: Indicates whether to add the drupal.tableresponsive library
  *   providing responsive tables.  Defaults to TRUE.
- * - #sticky: Indicates whether to add the drupal.tableheader library that makes
- *   table headers always visible at the top of the page. Defaults to FALSE.
+ * - #sticky: Indicates whether to make the table headers sticky at
+ *   the top of the page. Defaults to FALSE.
  * - #footer: Table footer rows, in the same format as the #rows property.
  * - #caption: A localized string for the <caption> tag.
  *
@@ -419,10 +419,7 @@ public static function preRenderTable($element) {
 
     // Add sticky headers, if applicable.
     if (count($element['#header']) && $element['#sticky']) {
-      $element['#attached']['library'][] = 'core/drupal.tableheader';
-      // Add 'sticky-enabled' class to the table to identify it for JS.
-      // This is needed to target tables constructed by this function.
-      $element['#attributes']['class'][] = 'sticky-enabled';
+      $element['#attributes']['class'][] = 'position-sticky';
     }
     // If the table has headers and it should react responsively to columns hidden
     // with the classes represented by the constants RESPONSIVE_PRIORITY_MEDIUM
diff --git a/core/misc/tableheader.js b/core/misc/tableheader.js
deleted file mode 100644
index 2c7624023c..0000000000
--- a/core/misc/tableheader.js
+++ /dev/null
@@ -1,335 +0,0 @@
-/**
- * @file
- * Sticky table headers.
- */
-
-(function ($, Drupal, displace) {
-  /**
-   * Constructor for the tableHeader object. Provides sticky table headers.
-   *
-   * TableHeader will make the current table header stick to the top of the page
-   * if the table is very long.
-   *
-   * @constructor Drupal.TableHeader
-   *
-   * @param {HTMLElement} table
-   *   DOM object for the table to add a sticky header to.
-   *
-   * @listens event:columnschange
-   */
-  function TableHeader(table) {
-    const $table = $(table);
-
-    /**
-     * @name Drupal.TableHeader#$originalTable
-     *
-     * @type {HTMLElement}
-     */
-    this.$originalTable = $table;
-
-    /**
-     * @type {jQuery}
-     */
-    this.$originalHeader = $table.children('thead');
-
-    /**
-     * @type {jQuery}
-     */
-    this.$originalHeaderCells = this.$originalHeader.find('> tr > th');
-
-    /**
-     * @type {null|boolean}
-     */
-    this.displayWeight = null;
-    this.$originalTable.addClass('sticky-table');
-    this.tableHeight = $table[0].clientHeight;
-    this.tableOffset = this.$originalTable.offset();
-
-    // React to columns change to avoid making checks in the scroll callback.
-    this.$originalTable.on(
-      'columnschange',
-      { tableHeader: this },
-      (e, display) => {
-        const tableHeader = e.data.tableHeader;
-        if (
-          tableHeader.displayWeight === null ||
-          tableHeader.displayWeight !== display
-        ) {
-          tableHeader.recalculateSticky();
-        }
-        tableHeader.displayWeight = display;
-      },
-    );
-
-    // Create and display sticky header.
-    this.createSticky();
-  }
-
-  // Helper method to loop through tables and execute a method.
-  function forTables(method, arg) {
-    const tables = TableHeader.tables;
-    const il = tables.length;
-    for (let i = 0; i < il; i++) {
-      tables[i][method](arg);
-    }
-  }
-
-  // Select and initialize sticky table headers.
-  function tableHeaderInitHandler(e) {
-    once('tableheader', $(e.data.context).find('table.sticky-enabled')).forEach(
-      (table) => {
-        TableHeader.tables.push(new TableHeader(table));
-      },
-    );
-    forTables('onScroll');
-  }
-
-  /**
-   * Attaches sticky table headers.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches the sticky table header behavior.
-   */
-  Drupal.behaviors.tableHeader = {
-    attach(context) {
-      $(window).one(
-        'scroll.TableHeaderInit',
-        { context },
-        tableHeaderInitHandler,
-      );
-    },
-  };
-
-  function scrollValue(position) {
-    return document.documentElement[position] || document.body[position];
-  }
-
-  function tableHeaderResizeHandler(e) {
-    forTables('recalculateSticky');
-  }
-
-  function tableHeaderOnScrollHandler(e) {
-    forTables('onScroll');
-  }
-
-  function tableHeaderOffsetChangeHandler(e, offsets) {
-    forTables('stickyPosition', offsets.top);
-  }
-
-  // Bind event that need to change all tables.
-  $(window).on({
-    /**
-     * When resizing table width can change, recalculate everything.
-     *
-     * @ignore
-     */
-    'resize.TableHeader': tableHeaderResizeHandler,
-
-    /**
-     * Bind only one event to take care of calling all scroll callbacks.
-     *
-     * @ignore
-     */
-    'scroll.TableHeader': tableHeaderOnScrollHandler,
-  });
-  // Bind to custom Drupal events.
-  $(document).on({
-    /**
-     * Recalculate columns width when window is resized, when show/hide weight
-     * is triggered, or when toolbar tray is toggled.
-     *
-     * @ignore
-     */
-    'columnschange.TableHeader drupalToolbarTrayChange':
-      tableHeaderResizeHandler,
-
-    /**
-     * Recalculate TableHeader.topOffset when viewport is resized.
-     *
-     * @ignore
-     */
-    'drupalViewportOffsetChange.TableHeader': tableHeaderOffsetChangeHandler,
-  });
-
-  /**
-   * Store the state of TableHeader.
-   */
-  $.extend(
-    TableHeader,
-    /** @lends Drupal.TableHeader */ {
-      /**
-       * This will store the state of all processed tables.
-       *
-       * @type {Array.<Drupal.TableHeader>}
-       */
-      tables: [],
-    },
-  );
-
-  /**
-   * Extend TableHeader prototype.
-   */
-  $.extend(
-    TableHeader.prototype,
-    /** @lends Drupal.TableHeader# */ {
-      /**
-       * Minimum height in pixels for the table to have a sticky header.
-       *
-       * @type {number}
-       */
-      minHeight: 100,
-
-      /**
-       * Absolute position of the table on the page.
-       *
-       * @type {?Drupal~displaceOffset}
-       */
-      tableOffset: null,
-
-      /**
-       * Absolute position of the table on the page.
-       *
-       * @type {?number}
-       */
-      tableHeight: null,
-
-      /**
-       * Boolean storing the sticky header visibility state.
-       *
-       * @type {boolean}
-       */
-      stickyVisible: false,
-
-      /**
-       * Create the duplicate header.
-       */
-      createSticky() {
-        // For caching purposes.
-        this.$html = $('html');
-        // Clone the table header so it inherits original jQuery properties.
-        const $stickyHeader = this.$originalHeader.clone(true);
-        // Hide the table to avoid a flash of the header clone upon page load.
-        this.$stickyTable = $(
-          '<table class="sticky-header" style="visibility: hidden; position: fixed; top: 0;"></table>',
-        )
-          .append($stickyHeader)
-          .insertBefore(this.$originalTable);
-
-        this.$stickyHeaderCells = $stickyHeader.find('> tr > th');
-
-        // Initialize all computations.
-        this.recalculateSticky();
-      },
-
-      /**
-       * Set absolute position of sticky.
-       *
-       * @param {number} offsetTop
-       *   The top offset for the sticky header.
-       * @param {number} offsetLeft
-       *   The left offset for the sticky header.
-       *
-       * @return {jQuery}
-       *   The sticky table as a jQuery collection.
-       */
-      stickyPosition(offsetTop, offsetLeft) {
-        const css = {};
-        if (typeof offsetTop === 'number') {
-          css.top = `${offsetTop}px`;
-        }
-        if (typeof offsetLeft === 'number') {
-          css.left = `${this.tableOffset.left - offsetLeft}px`;
-        }
-        this.$html[0].style.scrollPaddingTop =
-          displace.offsets.top +
-          (this.stickyVisible ? this.$stickyTable.height() : 0);
-
-        Object.assign(this.$stickyTable[0].style, css);
-
-        return this.$stickyTable;
-      },
-
-      /**
-       * Returns true if sticky is currently visible.
-       *
-       * @return {boolean}
-       *   The visibility status.
-       */
-      checkStickyVisible() {
-        const scrollTop = scrollValue('scrollTop');
-        const tableTop = this.tableOffset.top - displace.offsets.top;
-        const tableBottom = tableTop + this.tableHeight;
-        let visible = false;
-
-        if (tableTop < scrollTop && scrollTop < tableBottom - this.minHeight) {
-          visible = true;
-        }
-
-        this.stickyVisible = visible;
-        return visible;
-      },
-
-      /**
-       * Check if sticky header should be displayed.
-       *
-       * This function is throttled to once every 250ms to avoid unnecessary
-       * calls.
-       *
-       * @param {jQuery.Event} e
-       *   The scroll event.
-       */
-      onScroll(e) {
-        this.checkStickyVisible();
-        // Track horizontal positioning relative to the viewport.
-        this.stickyPosition(null, scrollValue('scrollLeft'));
-        this.$stickyTable[0].style.visibility = this.stickyVisible
-          ? 'visible'
-          : 'hidden';
-      },
-
-      /**
-       * Event handler: recalculates position of the sticky table header.
-       *
-       * @param {jQuery.Event} event
-       *   Event being triggered.
-       */
-      recalculateSticky(event) {
-        // Update table size.
-        this.tableHeight = this.$originalTable[0].clientHeight;
-
-        // Update offset top.
-        displace.offsets.top = displace.calculateOffset('top');
-        this.tableOffset = this.$originalTable.offset();
-        this.stickyPosition(displace.offsets.top, scrollValue('scrollLeft'));
-
-        // Update columns width.
-        let $that = null;
-        let $stickyCell = null;
-        let display = null;
-        // Resize header and its cell widths.
-        // Only apply width to visible table cells. This prevents the header from
-        // displaying incorrectly when the sticky header is no longer visible.
-        const il = this.$originalHeaderCells.length;
-        for (let i = 0; i < il; i++) {
-          $that = $(this.$originalHeaderCells[i]);
-          $stickyCell = this.$stickyHeaderCells.eq($that.index());
-          display = window.getComputedStyle($that[0]).display;
-          if (display !== 'none') {
-            Object.assign($stickyCell[0].style, {
-              width: window.getComputedStyle($that[0]).width,
-              display,
-            });
-          } else {
-            $stickyCell[0].style.display = 'none';
-          }
-        }
-        this.$stickyTable[0].style.width = this.$originalTable.outerWidth();
-      },
-    },
-  );
-
-  // Expose constructor in the public space.
-  Drupal.TableHeader = TableHeader;
-})(jQuery, Drupal, window.Drupal.displace);
diff --git a/core/modules/block/src/BlockListBuilder.php b/core/modules/block/src/BlockListBuilder.php
index cf2dfaf45c..f1652f883c 100644
--- a/core/modules/block/src/BlockListBuilder.php
+++ b/core/modules/block/src/BlockListBuilder.php
@@ -125,7 +125,6 @@ public function getFormId() {
    * {@inheritdoc}
    */
   public function buildForm(array $form, FormStateInterface $form_state) {
-    $form['#attached']['library'][] = 'core/drupal.tableheader';
     $form['#attached']['library'][] = 'block/drupal.block';
     $form['#attached']['library'][] = 'block/drupal.block.admin';
     $form['#attributes']['class'][] = 'clearfix';
diff --git a/core/modules/views/views.theme.inc b/core/modules/views/views.theme.inc
index e048c71473..fbdff31fd8 100644
--- a/core/modules/views/views.theme.inc
+++ b/core/modules/views/views.theme.inc
@@ -649,7 +649,6 @@ function template_preprocess_views_view_table(&$variables) {
 
   $variables['sticky'] = FALSE;
   if (!empty($options['sticky'])) {
-    $variables['view']->element['#attached']['library'][] = 'core/drupal.tableheader';
     $variables['sticky'] = TRUE;
   }
 
diff --git a/core/themes/claro/src/ClaroPreRender.php b/core/themes/claro/src/ClaroPreRender.php
index e18d0906c9..2a8ec471dd 100644
--- a/core/themes/claro/src/ClaroPreRender.php
+++ b/core/themes/claro/src/ClaroPreRender.php
@@ -189,17 +189,6 @@ public static function messagePlaceholder(array $element) {
     return $element;
   }
 
-  /**
-   * Prerender callback for table elements.
-   */
-  public static function tablePositionSticky(array $element) {
-    if (isset($element['#attributes']['class']) && in_array('sticky-enabled', $element['#attributes']['class'])) {
-      unset($element['#attributes']['class'][array_search('sticky-enabled', $element['#attributes']['class'])]);
-      $element['#attributes']['class'][] = 'position-sticky';
-    }
-    return $element;
-  }
-
   /**
    * {@inheritdoc}
    */
