diff --git a/dataframe-learn.cabal b/dataframe-learn.cabal
--- a/dataframe-learn.cabal
+++ b/dataframe-learn.cabal
@@ -1,6 +1,6 @@
 cabal-version:      3.4
 name:               dataframe-learn
-version:            2.1.0.1
+version:            2.2.0.0
 synopsis:           Interpretable, expression-returning machine learning for the dataframe ecosystem.
 description:
     A small scikit-learn-style ML library where every model returns both an
@@ -61,8 +61,8 @@
                         containers >= 0.6.7 && < 0.10,
                         parallel >= 3.3 && < 4,
                         random >= 1.2 && < 2,
-                        dataframe-core >= 2.1 && < 2.2,
-                        dataframe-operations >= 2.1 && < 2.2,
+                        dataframe-core >= 2.2 && < 2.3,
+                        dataframe-operations >= 2.2 && < 2.3,
                         text >= 2.1 && < 3,
                         vector >= 0.13 && < 0.15,
                         vector-algorithms >= 0.9 && < 0.11
@@ -105,11 +105,11 @@
                         containers >= 0.6.7 && < 0.10,
                         parallel >= 3.3 && < 4,
                         random >= 1.2 && < 2,
-                        dataframe-core >= 2.1 && < 2.2,
-                        dataframe-core >= 2.1 && < 2.2,
-                        dataframe-operations >= 2.1 && < 2.2,
-                        dataframe-operations >= 2.1 && < 2.2,
-                        dataframe-expr-serializer >= 1.2 && < 1.3,
+                        dataframe-core >= 2.2 && < 2.3,
+                        dataframe-core >= 2.2 && < 2.3,
+                        dataframe-operations >= 2.2 && < 2.3,
+                        dataframe-operations >= 2.2 && < 2.3,
+                        dataframe-expr-serializer >= 1.2.0.1 && < 1.3,
                         dataframe-learn:internal,
                         text >= 2.1 && < 3,
                         vector >= 0.13 && < 0.15
@@ -140,13 +140,13 @@
                         aeson >= 0.11.0.0 && < 3,
                         bytestring >= 0.11 && < 0.14,
                         containers >= 0.6.7 && < 0.10,
-                        dataframe-core >= 2.1 && < 2.2,
-                        dataframe-core >= 2.1 && < 2.2,
-                        dataframe-csv >= 2.2 && < 2.3,
+                        dataframe-core >= 2.2 && < 2.3,
+                        dataframe-core >= 2.2 && < 2.3,
+                        dataframe-csv >= 2.3 && < 2.4,
                         dataframe-learn,
                         dataframe-learn:internal,
-                        dataframe-operations >= 2.1 && < 2.2,
-                        dataframe-operations >= 2.1 && < 2.2,
+                        dataframe-operations >= 2.2 && < 2.3,
+                        dataframe-operations >= 2.2 && < 2.3,
                         HUnit >= 1.6 && < 1.8,
                         QuickCheck >= 2 && < 3,
                         random >= 1 && < 2,
diff --git a/src/DataFrame/Model.hs b/src/DataFrame/Model.hs
--- a/src/DataFrame/Model.hs
+++ b/src/DataFrame/Model.hs
@@ -57,11 +57,13 @@
 import DataFrame.Typed.Schema (AllDouble)
 import DataFrame.Typed.Types (AsTExpr, TExpr (..), ToTExpr (..), TypedDataFrame)
 
+import GHC.TypeLits (Symbol)
+
 {- | A model trained on a typed frame, carrying the schema @cols@ as a phantom so
 its 'predict' yields a typed 'TExpr'. Use 'fittedModel' to recover the bare model
 record (coefficients, etc.).
 -}
-newtype Fitted (cols :: [Type]) model = Fitted {fittedModel :: model}
+newtype Fitted (cols :: [(Symbol, Type)]) model = Fitted {fittedModel :: model}
 
 {- | The type 'fit' returns for a given frame source: the bare @model@ for an
 untyped 'DataFrame', or a schema-tagged 'Fitted' for a 'TypedDataFrame'. Training
