diff --git a/meshmode/discretization/__init__.py b/meshmode/discretization/__init__.py
index d19e5b92e1f58bf21416e09e8e23b734f24db206..31f2deee1c9454ee7aa3a2fc8e7028d1c4282680 100644
--- a/meshmode/discretization/__init__.py
+++ b/meshmode/discretization/__init__.py
@@ -126,6 +126,12 @@ class InterpolatoryElementGroupBase(ElementGroupBase):
     """A subclass of :class:`ElementGroupBase` that is equipped with a
     function space.
 
+    .. method:: mode_ids()
+
+        Return an immutable sequence of opaque (hashable) mode identifiers,
+        one per element of the :meth:`basis`. The meaning of the mode
+        identifiers is defined by the concrete element group.
+
     .. method:: basis()
 
         Returns a :class:`list` of basis functions that take arrays
diff --git a/meshmode/discretization/poly_element.py b/meshmode/discretization/poly_element.py
index e317e31130237ad2adf5173af4a7c0d23d0f2b9d..300c00fb97d2c57350ddc481a34ca4d9885b677c 100644
--- a/meshmode/discretization/poly_element.py
+++ b/meshmode/discretization/poly_element.py
@@ -110,11 +110,22 @@ class PolynomialSimplexElementGroupBase(PolynomialElementGroupBase,
     def is_orthogonal_basis(self):
         return self.dim <= 3
 
-    def basis(self):
+    @memoize_method
+    def _mode_ids_and_basis(self):
+        # for now, see https://gitlab.tiker.net/inducer/modepy/-/merge_requests/14
+        import modepy.modes as modes
         if self.dim <= 3:
-            return mp.simplex_onb(self.dim, self.order)
+            return modes.simplex_onb_with_mode_ids(self.dim, self.order)
         else:
-            return mp.simplex_monomial_basis(self.dim, self.order)
+            return modes.simplex_monomial_basis_with_mode_ids(self.dim, self.order)
+
+    def basis(self):
+        mode_ids, basis = self._mode_ids_and_basis()
+        return basis
+
+    def mode_ids(self):
+        mode_ids, basis = self._mode_ids_and_basis()
+        return mode_ids
 
     def grad_basis(self):
         if self.dim <= 3:
@@ -129,6 +140,10 @@ class InterpolatoryQuadratureSimplexElementGroup(PolynomialSimplexElementGroupBa
     hence usable for differentiation and interpolation.
 
     No interpolation nodes are present on the boundary of the simplex.
+
+    The :meth:`~meshmode.discretization.InterpolatoryElementGroupBase.mode_ids`
+    are a tuple (one entry per dimension) of directional polynomial degrees
+    on the reference element.
     """
 
     @memoize_method
@@ -165,6 +180,10 @@ class QuadratureSimplexElementGroup(SimplexElementGroupBase):
     quadarature, but is not necessarily usable for interpolation.
 
     No interpolation nodes are present on the boundary of the simplex.
+
+    The :meth:`~meshmode.discretization.InterpolatoryElementGroupBase.mode_ids`
+    are a tuple (one entry per dimension) of directional polynomial degrees
+    on the reference element.
     """
 
     @memoize_method
@@ -211,6 +230,10 @@ class PolynomialWarpAndBlendElementGroup(_MassMatrixQuadratureElementGroup):
     phenomena. Nodes are present on the boundary of the simplex.
 
     Uses :func:`modepy.warp_and_blend_nodes`.
+
+    The :meth:`~meshmode.discretization.InterpolatoryElementGroupBase.mode_ids`
+    are a tuple (one entry per dimension) of directional polynomial degrees
+    on the reference element.
     """
     @property
     @memoize_method
@@ -238,6 +261,10 @@ class PolynomialRecursiveNodesElementGroup(_MassMatrixQuadratureElementGroup):
 
     Requires :mod:`recursivenodes` to be installed.
 
+    The :meth:`~meshmode.discretization.InterpolatoryElementGroupBase.mode_ids`
+    are a tuple (one entry per dimension) of directional polynomial degrees
+    on the reference element.
+
     .. [Isaac20] Tobin Isaac. Recursive, parameter-free, explicitly defined
         interpolation nodes for simplices.
         `Arxiv preprint <https://arxiv.org/abs/2002.09421>`__.
@@ -268,6 +295,10 @@ class PolynomialEquidistantSimplexElementGroup(_MassMatrixQuadratureElementGroup
     interpolation. Interpolation nodes are present on the boundary of the
     simplex.
 
+    The :meth:`~meshmode.discretization.InterpolatoryElementGroupBase.mode_ids`
+    are a tuple (one entry per dimension) of directional polynomial degrees
+    on the reference element.
+
     .. versionadded:: 2016.1
     """
     @property