diff --git a/frontend/src/metabase-lib/metadata/Database.ts b/frontend/src/metabase-lib/metadata/Database.ts
index 773a3aba76589db0be374887be3485a7b9fc52db..ee695a95dad8bceb9e9822c726b1d75bbe77818d 100644
--- a/frontend/src/metabase-lib/metadata/Database.ts
+++ b/frontend/src/metabase-lib/metadata/Database.ts
@@ -64,7 +64,7 @@ class Database {
     return this.tablesLookup();
   }
 
-  hasFeature(feature: string | undefined) {
+  hasFeature(feature: string | null | undefined) {
     if (!feature) {
       return true;
     }
diff --git a/frontend/src/metabase-lib/metadata/Database.unit.spec.ts b/frontend/src/metabase-lib/metadata/Database.unit.spec.ts
index 7157cf0c04899f89c2aa5f414db95e1b55cba2f6..074d72afbf60573f4494e009637c255654bf7a1e 100644
--- a/frontend/src/metabase-lib/metadata/Database.unit.spec.ts
+++ b/frontend/src/metabase-lib/metadata/Database.unit.spec.ts
@@ -1,272 +1,260 @@
-// eslint-disable-next-line @typescript-eslint/ban-ts-comment
-// @ts-nocheck
-import Question from "../Question";
-import Database from "./Database";
-import Schema from "./Schema";
-import Metadata from "./Metadata";
-import Table from "./Table";
+import { Database } from "metabase-types/api";
+import { createMockMetadata } from "__support__/metadata";
+import { createMockDatabase, createMockTable } from "metabase-types/api/mocks";
+import NativeQuery from "metabase-lib/queries/NativeQuery";
+import StructuredQuery from "metabase-lib/queries/StructuredQuery";
+
+interface SetupOpts {
+  database?: Database;
+  otherDatabases?: Database[];
+}
+
+const setup = ({
+  database = createMockDatabase(),
+  otherDatabases = [],
+}: SetupOpts = {}) => {
+  const metadata = createMockMetadata({
+    databases: [database, ...otherDatabases],
+  });
+
+  const instance = metadata.database(database.id);
+  if (!instance) {
+    throw new TypeError();
+  }
+
+  return instance;
+};
 
 describe("Database", () => {
   describe("instantiation", () => {
-    it("should create an instance of Schema", () => {
-      expect(new Database()).toBeInstanceOf(Database);
+    it("should create an instance of Database", () => {
+      const database = setup({
+        database: createMockDatabase({}),
+      });
+      expect(database).toBeDefined();
     });
   });
+
   describe("displayName", () => {
     it("should return the name prop", () => {
-      expect(
-        new Database({
+      const database = setup({
+        database: createMockDatabase({
           name: "foo",
-        }).displayName(),
-      ).toBe("foo");
+        }),
+      });
+
+      expect(database.displayName()).toBe("foo");
     });
   });
+
   describe("schema", () => {
-    let schema;
-    let database;
-    beforeEach(() => {
-      schema = new Schema({
-        id: "123:foo",
-      });
-      const metadata = new Metadata({
-        schemas: {
-          "123:foo": schema,
-        },
-      });
-      database = new Database({
-        id: 123,
-        metadata,
-      });
-    });
     it("should return the schema with the given name", () => {
-      expect(database.schema("foo")).toBe(schema);
-    });
-    it("should return null when the given schema name doesn not match a schema", () => {
+      const database = setup({
+        database: createMockDatabase({
+          tables: [
+            createMockTable({
+              schema: "public",
+            }),
+          ],
+        }),
+      });
+
+      expect(database.schema("public")).toBeDefined();
       expect(database.schema("bar")).toBe(null);
     });
   });
+
   describe("schemaNames", () => {
     it("should return a list of schemaNames", () => {
-      const database = new Database({
-        id: 123,
-        schemas: [
-          new Schema({
-            id: "123:foo",
-            name: "foo",
-          }),
-          new Schema({
-            id: "123:bar",
-            name: "bar",
-          }),
-        ],
+      const database = setup({
+        database: createMockDatabase({
+          tables: [
+            createMockTable({
+              id: 1,
+              schema: "foo",
+            }),
+            createMockTable({
+              id: 2,
+              schema: "bar",
+            }),
+          ],
+        }),
       });
+
       expect(database.schemaNames()).toEqual(["bar", "foo"]);
     });
   });
+
   describe("tablesLookup", () => {
     it("should return a map of tables keyed by id", () => {
-      const table1 = new Table({
-        id: 1,
-      });
-      const table2 = new Table({
-        id: 2,
-      });
-      expect(
-        new Database({
-          tables: [],
-        }).tablesLookup(),
-      ).toEqual({});
-      expect(
-        new Database({
-          tables: [table1, table2],
-        }).tablesLookup(),
-      ).toEqual({
-        1: table1,
-        2: table2,
+      const database = setup({
+        database: createMockDatabase({
+          tables: [
+            createMockTable({
+              id: 1,
+            }),
+            createMockTable({
+              id: 2,
+            }),
+          ],
+        }),
       });
+
+      const lookup = database.tablesLookup();
+      expect(lookup[1]).toBeDefined();
+      expect(lookup[2]).toBeDefined();
+      expect(lookup[1]).toBe(database.metadata?.table(1));
+      expect(lookup[2]).toBe(database.metadata?.table(2));
     });
   });
+
   describe("hasFeature", () => {
     it("returns true when given a falsy `feature`", () => {
-      expect(new Database({}).hasFeature(null)).toBe(true);
-      expect(new Database({}).hasFeature("")).toBe(true);
+      const database = setup({
+        database: createMockDatabase(),
+      });
+
+      expect(database.hasFeature(null)).toBe(true);
+      expect(database.hasFeature("")).toBe(true);
     });
+
     it("should return true when given `feature` is found within the `features` on the instance", () => {
-      expect(
-        new Database({
-          features: ["foo"],
-        }).hasFeature("foo"),
-      ).toBe(true);
+      const database = setup({
+        database: createMockDatabase({
+          features: ["inner-join"],
+        }),
+      });
+
+      expect(database.hasFeature("inner-join")).toBe(true);
     });
+
     it("should return false when given `feature` is not found within the `features` on the instance", () => {
-      expect(
-        new Database({
-          features: ["foo"],
-        }).hasFeature("bar"),
-      ).toBe(false);
-    });
-    it("should return false for 'join' even when it exists in `features`", () => {
-      expect(
-        new Database({
-          features: ["join"],
-        }).hasFeature("join"),
-      ).toBe(false);
-    });
-    it("should return true for 'join' for a set of other values", () => {
-      ["left-join", "right-join", "inner-join", "full-join"].forEach(
-        feature => {
-          expect(
-            new Database({
-              features: [feature],
-            }).hasFeature("join"),
-          ).toBe(true);
-        },
-      );
+      const database = setup({
+        database: createMockDatabase({
+          features: ["inner-join"],
+        }),
+      });
+
+      expect(database.hasFeature("persist-models")).toBe(false);
     });
+
+    it.each(["left-join", "right-join", "inner-join", "full-join"] as const)(
+      "should return true for 'join' for %s",
+      feature => {
+        const database = setup({
+          database: createMockDatabase({
+            features: [feature],
+          }),
+        });
+
+        expect(database.hasFeature("join")).toBe(true);
+      },
+    );
   });
+
   describe("supportsPivots", () => {
     it("returns true when `expressions` and `left-join` exist in `features`", () => {
-      expect(
-        new Database({
-          features: ["foo", "left-join"],
-        }).supportsPivots(),
-      ).toBe(false);
-      expect(
-        new Database({
-          features: ["expressions", "right-join"],
-        }).supportsPivots(),
-      ).toBe(false);
-      expect(
-        new Database({
+      const database = setup({
+        database: createMockDatabase({
           features: ["expressions", "left-join"],
-        }).supportsPivots(),
-      ).toBe(true);
+        }),
+      });
+
+      expect(database.supportsPivots()).toBe(true);
+    });
+
+    it("returns false when `expressions` and `left-join` not exist in `features`", () => {
+      const database = setup({
+        database: createMockDatabase({
+          features: ["schemas", "persist-models"],
+        }),
+      });
+
+      expect(database.supportsPivots()).toBe(false);
     });
   });
+
   describe("question", () => {
     it("should create a question using the `metadata` found on the Database instance", () => {
-      const metadata = new Metadata();
-      const database = new Database({
-        metadata,
-      });
+      const database = setup();
       const question = database.question();
-      expect(question.metadata()).toBe(metadata);
+
+      expect(question.query()).toBeInstanceOf(StructuredQuery);
+      expect(question.metadata()).toEqual(database.metadata);
     });
+
     it("should create a question using the given Database instance's id in the question's query", () => {
-      const database = new Database({
-        id: 123,
-      });
-      expect(database.question().datasetQuery()).toEqual({
-        database: 123,
-        query: {
-          "source-table": undefined,
-        },
-        type: "query",
+      const table = createMockTable();
+      const database = setup({
+        database: createMockDatabase({ tables: [table] }),
       });
-      expect(
-        database
-          .question({
-            foo: "bar",
-          })
-          .datasetQuery(),
-      ).toEqual({
-        database: 123,
-        query: {
-          foo: "bar",
-        },
-        type: "query",
+      const question = database.question({
+        "source-table": table.id,
       });
+
+      expect(question.databaseId()).toBe(database.id);
+      expect(question.tableId()).toBe(table.id);
     });
   });
+
   describe("nativeQuestion", () => {
     it("should create a native question using the `metadata` found on the Database instance", () => {
-      const metadata = new Metadata();
-      const database = new Database({
-        metadata,
-      });
+      const database = setup();
       const question = database.nativeQuestion();
-      expect(question.metadata()).toBe(metadata);
+
+      expect(question.query()).toBeInstanceOf(NativeQuery);
+      expect(question.metadata()).toBe(database.metadata);
     });
+
     it("should create a native question using the given Database instance's id in the question's query", () => {
-      const database = new Database({
-        id: 123,
-      });
-      expect(database.nativeQuestion().datasetQuery()).toEqual({
-        database: 123,
-        native: {
-          query: "",
-          "template-tags": {},
-        },
-        type: "native",
-      });
-      expect(
-        database
-          .nativeQuestion({
-            foo: "bar",
-          })
-          .datasetQuery(),
-      ).toEqual({
-        database: 123,
-        native: {
-          query: "",
-          "template-tags": {},
-          foo: "bar",
-        },
-        type: "native",
-      });
+      const database = setup();
+      const question = database.nativeQuestion({ query: "SELECT 1" });
+
+      const query = question.query() as NativeQuery;
+      expect(query.queryText()).toBe("SELECT 1");
     });
   });
+
   describe("newQuestion", () => {
     it("should return new question with defaulted query and display", () => {
-      const database = new Database({
-        id: 123,
-      });
-      Question.prototype.setDefaultQuery = jest.fn(function () {
-        return this;
-      });
-      Question.prototype.setDefaultDisplay = jest.fn(function () {
-        return this;
-      });
+      const database = setup();
       const question = database.newQuestion();
-      expect(question).toBeInstanceOf(Question);
-      expect(Question.prototype.setDefaultDisplay).toHaveBeenCalled();
-      expect(Question.prototype.setDefaultQuery).toHaveBeenCalled();
+
+      expect(question.display()).toBe("table");
     });
   });
+
   describe("savedQuestionsDatabase", () => {
     it("should return the 'fake' saved questions database", () => {
-      const database1 = new Database({
-        id: 1,
-      });
-      const database2 = new Database({
-        id: 2,
-        is_saved_questions: true,
-      });
-      const metadata = new Metadata({
-        databases: {
-          1: database1,
-          2: database2,
-        },
+      const database = setup({
+        database: createMockDatabase({ id: 1 }),
+        otherDatabases: [
+          createMockDatabase({ id: 2, is_saved_questions: true }),
+        ],
       });
-      database1.metadata = metadata;
-      expect(database1.savedQuestionsDatabase()).toBe(database2);
+
+      const savedQuestionsDatabase = database.savedQuestionsDatabase();
+      expect(savedQuestionsDatabase).toBeDefined();
+      expect(savedQuestionsDatabase).toBe(database.metadata?.database(2));
     });
   });
 
   describe("canWrite", () => {
     it("should be true for a db with write permissions", () => {
-      const database = new Database({
-        id: 1,
-        native_permissions: "write",
+      const database = setup({
+        database: createMockDatabase({
+          native_permissions: "write",
+        }),
       });
 
       expect(database.canWrite()).toBe(true);
     });
 
     it("should be false for a db without write permissions", () => {
-      const database = new Database({
-        id: 1,
-        native_permissions: "none",
+      const database = setup({
+        database: createMockDatabase({
+          native_permissions: "none",
+        }),
       });
 
       expect(database.canWrite()).toBe(false);
diff --git a/frontend/src/metabase-lib/metadata/Field.ts b/frontend/src/metabase-lib/metadata/Field.ts
index cf1ccef0679c51379fa79b3657433bd984d2f749..b484082d66ea83efd373d75f6b0bcbeda57bca50 100644
--- a/frontend/src/metabase-lib/metadata/Field.ts
+++ b/frontend/src/metabase-lib/metadata/Field.ts
@@ -69,7 +69,7 @@ const LONG_TEXT_MIN = 80;
  */
 
 class FieldInner extends Base {
-  id: number | FieldReference;
+  id: FieldId | FieldReference;
   name: string;
   display_name: string;
   description: string | null;
@@ -140,7 +140,7 @@ class FieldInner extends Base {
 
   displayName({
     includeSchema = false,
-    includeTable,
+    includeTable = false,
     includePath = true,
   } = {}) {
     let displayName = "";
diff --git a/frontend/src/metabase-lib/metadata/Field.unit.spec.ts b/frontend/src/metabase-lib/metadata/Field.unit.spec.ts
index 0702654f5ca8459221c63f127f494d8e7c17d836..571b2103f3231af2445cca820df52c5c19d87085 100644
--- a/frontend/src/metabase-lib/metadata/Field.unit.spec.ts
+++ b/frontend/src/metabase-lib/metadata/Field.unit.spec.ts
@@ -1,142 +1,180 @@
-// eslint-disable-next-line @typescript-eslint/ban-ts-comment
-// @ts-nocheck
-import Dimension from "../Dimension";
-import Field from "./Field";
-import Table from "./Table";
-import Schema from "./Schema";
-import Metadata from "./Metadata";
-import Base from "./Base";
-import { createMockConcreteField } from "./mocks";
+import { Database, Field, Table } from "metabase-types/api";
+import {
+  createMockDateTimeFieldFingerprint,
+  createMockField,
+  createMockFieldDimension,
+  createMockTable,
+} from "metabase-types/api/mocks";
+import { createMockMetadata } from "__support__/metadata";
+import { TYPE } from "metabase-lib/types/constants";
+
+const FIELD_ID = 1;
+
+interface SetupOpts {
+  databases?: Database[];
+  tables?: Table[];
+  fields?: Field[];
+}
+
+const setup = ({ databases = [], tables = [], fields = [] }: SetupOpts) => {
+  const metadata = createMockMetadata({
+    databases,
+    tables,
+    fields,
+  });
+
+  const instance = metadata.field(FIELD_ID);
+  if (!instance) {
+    throw TypeError();
+  }
+
+  return instance;
+};
 
 describe("Field", () => {
   describe("instantiation", () => {
     it("should create an instance of Schema", () => {
-      expect(new Field()).toBeInstanceOf(Field);
-    });
+      const field = setup({
+        fields: [
+          createMockField({
+            id: FIELD_ID,
+          }),
+        ],
+      });
 
-    it("should add `object` props to the instance (because it extends Base)", () => {
-      expect(new Field()).toBeInstanceOf(Base);
-      expect(
-        new Field({
-          foo: "bar",
-        }),
-      ).toHaveProperty("foo", "bar");
+      expect(field).toBeDefined();
     });
   });
 
   describe("parent", () => {
     it("should return null when `metadata` does not exist on instance", () => {
-      expect(new Field().parent()).toBeNull();
+      const field = setup({
+        fields: [
+          createMockField({
+            id: FIELD_ID,
+          }),
+        ],
+      });
+
+      expect(field.parent()).toBeNull();
     });
 
     it("should return the field that matches the instance's `parent_id` when `metadata` exists on the instance", () => {
-      const parentField = new Field({
-        id: 1,
-      });
-      const metadata = new Metadata({
-        fields: {
-          1: parentField,
-        },
-      });
-      const field = new Field({
-        parent_id: 1,
-        id: 2,
-        metadata,
+      const field = setup({
+        fields: [
+          createMockField({
+            id: FIELD_ID,
+            parent_id: 2,
+          }),
+          createMockField({
+            id: 2,
+          }),
+        ],
       });
-      expect(field.parent()).toBe(parentField);
+
+      expect(field.parent()).toBeDefined();
+      expect(field.parent()).toBe(field.metadata?.field(2));
     });
   });
 
   describe("path", () => {
     it("should return list of fields starting with instance, ending with root parent", () => {
-      const rootField = new Field({
-        id: 1,
-      });
-      const parentField = new Field({
-        id: 2,
-        parent_id: 1,
-      });
-      const metadata = new Metadata({
-        fields: {
-          1: rootField,
-          2: parentField,
-        },
-      });
-      parentField.metadata = metadata;
-      rootField.metadata = metadata;
-      const field = new Field({
-        parent_id: 2,
-        id: 3,
-        metadata,
-      });
-      expect(field.path()).toEqual([rootField, parentField, field]);
+      const field = setup({
+        fields: [
+          createMockField({
+            id: FIELD_ID,
+            parent_id: 2,
+          }),
+          createMockField({
+            id: 2,
+            parent_id: 3,
+          }),
+          createMockField({
+            id: 3,
+          }),
+        ],
+      });
+
+      const metadata = field.metadata;
+      expect(field.path()).toEqual([
+        metadata?.field(3),
+        metadata?.field(2),
+        metadata?.field(1),
+      ]);
     });
   });
 
   describe("displayName", () => {
-    it("should return a field's display name", () => {
-      expect(
-        new Field({
-          name: "foo",
-        }).displayName(),
-      ).toBe("foo");
+    it("should return a field's name", () => {
+      const field = setup({
+        fields: [
+          createMockField({
+            id: FIELD_ID,
+            name: "foo",
+            display_name: "",
+          }),
+        ],
+      });
+
+      expect(field.displayName()).toBe("foo");
     });
 
     it("should prioritize the `display_name` field over `name`", () => {
-      expect(
-        new Field({
-          display_name: "bar",
-          name: "foo",
-        }).displayName(),
-      ).toBe("bar");
+      const field = setup({
+        fields: [
+          createMockField({
+            id: FIELD_ID,
+            name: "foo",
+            display_name: "bar",
+          }),
+        ],
+      });
+
+      expect(field.displayName()).toBe("bar");
     });
 
     it("should prioritize the name in the field's `dimensions` property if it has one", () => {
-      const field = new Field({
-        dimensions: [
-          {
-            name: "dimensions",
-          },
+      const field = setup({
+        fields: [
+          createMockField({
+            id: FIELD_ID,
+            display_name: "display",
+            dimensions: [
+              createMockFieldDimension({
+                name: "dimensions",
+              }),
+            ],
+          }),
         ],
-        display_name: "display",
       });
+
       expect(field.displayName()).toBe("dimensions");
     });
 
     describe("includePath flag", () => {
-      let field;
-      beforeEach(() => {
-        const rootField = new Field({
-          id: 1,
-          name: "rootField",
-        });
-        const parentField = new Field({
-          id: 2,
-          parent_id: 1,
-          name: "parentField",
-        });
-        const metadata = new Metadata({
-          fields: {
-            1: rootField,
-            2: parentField,
-          },
-        });
-        parentField.metadata = metadata;
-        rootField.metadata = metadata;
-        field = new Field({
-          parent_id: 2,
-          id: 3,
-          metadata,
-          name: "field",
-        });
+      const field = setup({
+        fields: [
+          createMockField({
+            id: FIELD_ID,
+            parent_id: 2,
+            display_name: "field",
+          }),
+          createMockField({
+            id: 2,
+            parent_id: 3,
+            display_name: "parentField",
+          }),
+          createMockField({
+            id: 3,
+            display_name: "rootField",
+          }),
+        ],
       });
 
       it("should add parent field display names to the field's display name when enabled", () => {
-        expect(
-          field.displayName({
-            includePath: true,
-          }),
-        ).toBe("rootField: parentField: field");
+        expect(field.displayName({ includePath: true })).toBe(
+          "rootField: parentField: field",
+        );
       });
 
       it("should be enabled by default", () => {
@@ -148,53 +186,54 @@ describe("Field", () => {
       });
 
       it("should exclude parent field display names when disabled", () => {
-        expect(
-          field.displayName({
-            includePath: false,
-          }),
-        ).toBe("field");
+        expect(field.displayName({ includePath: false })).toBe("field");
       });
     });
 
     describe("includeTable flag", () => {
-      let field;
-      beforeEach(() => {
-        field = new Field({
-          id: 1,
-          name: "field",
+      it("should do nothing when there is no table on the field instance", () => {
+        const field = setup({
+          fields: [
+            createMockField({
+              id: FIELD_ID,
+              display_name: "field",
+            }),
+          ],
         });
-      });
 
-      it("should do nothing when there is no table on the field instance", () => {
-        expect(
-          field.displayName({
-            includeTable: true,
-          }),
-        ).toBe("field");
+        expect(field.displayName({ includeTable: true })).toBe("field");
       });
 
       it("should add the table name to the start of the field name", () => {
-        field.table = new Table({
-          display_name: "table",
+        const field = setup({
+          tables: [
+            createMockTable({
+              display_name: "table",
+              fields: [
+                createMockField({
+                  id: FIELD_ID,
+                  display_name: "field",
+                }),
+              ],
+            }),
+          ],
         });
-        expect(
-          field.displayName({
-            includeTable: true,
-          }),
-        ).toBe("table → field");
+
+        expect(field.displayName({ includeTable: true })).toBe("table → field");
       });
     });
 
     describe("includeSchema flag", () => {
-      let field;
-      beforeEach(() => {
-        field = new Field({
-          id: 1,
-          name: "field",
+      it("won't do anything if enabled and includeTable is not enabled", () => {
+        const field = setup({
+          fields: [
+            createMockField({
+              id: FIELD_ID,
+              display_name: "field",
+            }),
+          ],
         });
-      });
 
-      it("won't do anything if enabled and includeTable is not enabled", () => {
         expect(
           field.displayName({
             includeSchema: true,
@@ -203,12 +242,21 @@ describe("Field", () => {
       });
 
       it("should add a combined schema + table display name to the start of the field name", () => {
-        field.table = new Table({
-          display_name: "table",
-          schema: new Schema({
-            name: "schema",
-          }),
+        const field = setup({
+          tables: [
+            createMockTable({
+              display_name: "table",
+              schema: "schema",
+              fields: [
+                createMockField({
+                  id: FIELD_ID,
+                  display_name: "field",
+                }),
+              ],
+            }),
+          ],
         });
+
         expect(
           field.displayName({
             includeTable: true,
@@ -221,43 +269,46 @@ describe("Field", () => {
 
   describe("targetObjectName", () => {
     it("should return the display name of the field stripped of an appended id", () => {
-      const field = new Field({
-        name: "field id",
+      const field = setup({
+        fields: [
+          createMockField({
+            id: FIELD_ID,
+            display_name: "field id",
+          }),
+        ],
       });
+
       expect(field.targetObjectName()).toBe("field");
     });
   });
 
   describe("dimension", () => {
-    it("should return the field's dimension when the id is an mbql field", () => {
-      const field = new Field({
-        id: ["field", 123, null],
-      });
-      const dimension = field.dimension();
-      expect(dimension).toBeInstanceOf(Dimension);
-      expect(dimension.fieldIdOrName()).toBe(123);
-    });
-
     it("should return the field's dimension when the id is not an mbql field", () => {
-      const field = new Field({
-        id: 123,
+      const field = setup({
+        fields: [
+          createMockField({
+            id: FIELD_ID,
+            display_name: "field id",
+          }),
+        ],
       });
+
       const dimension = field.dimension();
-      expect(dimension).toBeInstanceOf(Dimension);
-      expect(dimension.fieldIdOrName()).toBe(123);
+      expect(dimension.fieldIdOrName()).toBe(FIELD_ID);
     });
   });
 
   describe("getDefaultDateTimeUnit", () => {
     describe("when the field is of type `type/DateTime`", () => {
       it("should return 'day'", () => {
-        const field = new Field({
-          fingerprint: {
-            type: {
-              "type/Number": {},
-            },
-          },
+        const field = setup({
+          fields: [
+            createMockField({
+              id: FIELD_ID,
+            }),
+          ],
         });
+
         expect(field.getDefaultDateTimeUnit()).toBe("day");
       });
     });
@@ -265,207 +316,246 @@ describe("Field", () => {
 
   describe("when field is of type `type/DateTime`", () => {
     it("should return a time unit depending on the number of days in the 'fingerprint'", () => {
-      const field = new Field({
-        fingerprint: {
-          type: {
-            "type/DateTime": {
-              earliest: "2019-03-01T00:00:00Z",
-              latest: "2021-01-01T00:00:00Z",
+      const field = setup({
+        fields: [
+          createMockField({
+            id: FIELD_ID,
+            fingerprint: {
+              type: {
+                "type/DateTime": createMockDateTimeFieldFingerprint({
+                  earliest: "2019-03-01T00:00:00Z",
+                  latest: "2021-01-01T00:00:00Z",
+                }),
+              },
             },
-          },
-        },
+          }),
+        ],
       });
+
       expect(field.getDefaultDateTimeUnit()).toBe("month");
     });
   });
 
   describe("remappedField", () => {
     it("should return the 'human readable' field tied to the field's dimension", () => {
-      const field1 = new Field({
-        id: 1,
-      });
-      const field2 = new Field({
-        id: 2,
-      });
-      const metadata = new Metadata({
-        fields: {
-          1: field1,
-          2: field2,
-        },
-      });
-      const field = new Field({
-        id: 3,
-        dimensions: [
-          {
-            human_readable_field_id: 1,
-          },
+      const field = setup({
+        fields: [
+          createMockField({
+            id: FIELD_ID,
+            dimensions: [
+              createMockFieldDimension({
+                human_readable_field_id: 2,
+              }),
+            ],
+          }),
+          createMockField({
+            id: 2,
+          }),
         ],
       });
-      field.metadata = metadata;
-      expect(field.remappedField()).toBe(field1);
+
+      expect(field.remappedField()).toBeDefined();
+      expect(field.remappedField()).toBe(field.metadata?.field(2));
     });
 
     it("should return the field's name_field", () => {
-      const nameField = new Field();
-      const field = new Field({
-        id: 3,
-        name_field: nameField,
+      const field = setup({
+        fields: [
+          createMockField({
+            id: FIELD_ID,
+            name_field: createMockField({
+              id: 2,
+            }),
+          }),
+        ],
       });
-      expect(field.remappedField()).toBe(nameField);
+
+      expect(field.remappedField()).toBeDefined();
+      expect(field.remappedField()).toBe(field.metadata?.field(2));
     });
 
     it("should return null when the field has no name_field or no dimension with a 'human readable' field", () => {
-      expect(new Field().remappedField()).toBe(null);
+      const field = setup({
+        fields: [
+          createMockField({
+            id: FIELD_ID,
+          }),
+        ],
+      });
+
+      expect(field.remappedField()).toBe(null);
     });
   });
 
   describe("remappedValue", () => {
     it("should call a given value using the instance's remapping property", () => {
-      const field = new Field({
-        remapping: {
-          get: () => 1,
-        },
+      const field = setup({
+        fields: [
+          createMockField({
+            id: FIELD_ID,
+            remappings: [[2, "A"]],
+          }),
+        ],
       });
-      expect(field.remappedValue(2)).toBe(1);
+
+      expect(field.remappedValue(2)).toBe("A");
     });
 
     it("should convert a numeric field into a number if it is not a number", () => {
-      const field = new Field({
-        isNumeric: () => true,
-        remapping: {
-          get: num => num,
-        },
+      const field = setup({
+        fields: [
+          createMockField({
+            id: FIELD_ID,
+            base_type: TYPE.Number,
+            semantic_type: TYPE.Number,
+            remappings: [[2.5, "A"]],
+          }),
+        ],
       });
-      expect(field.remappedValue("2.5rem")).toBe(2.5);
+
+      expect(field.remappedValue("2.5rem")).toBe("A");
     });
   });
 
   describe("hasRemappedValue", () => {
     it("should call a given value using the instance's remapping property", () => {
-      const field = new Field({
-        remapping: {
-          has: () => true,
-        },
+      const field = setup({
+        fields: [
+          createMockField({
+            id: FIELD_ID,
+            remappings: [[2, "A"]],
+          }),
+        ],
       });
-      expect(field.hasRemappedValue(2)).toBe(true);
+
+      expect(field.hasRemappedValue(1)).toBeFalsy();
+      expect(field.hasRemappedValue(2)).toBeTruthy();
     });
 
-    it("should convert a numeric field into a number if it is not a number", () => {
-      const field = new Field({
-        isNumeric: () => true,
-        remapping: {
-          has: num => typeof num === "number",
-        },
+    it("should not convert a numeric field into a number if it is not a number", () => {
+      const field = setup({
+        fields: [
+          createMockField({
+            id: FIELD_ID,
+            remappings: [[2.5, "A"]],
+          }),
+        ],
       });
-      expect(field.hasRemappedValue("2.5rem")).toBe(true);
+
+      expect(field.remappedValue("2.5rem")).toBeFalsy();
     });
   });
 
   describe("isSearchable", () => {
     it("should be true when the field is a string", () => {
-      const field = new Field({
-        isString: () => true,
+      const field = setup({
+        fields: [
+          createMockField({
+            id: FIELD_ID,
+            base_type: TYPE.Text,
+            semantic_type: TYPE.Text,
+          }),
+        ],
       });
+
       expect(field.isSearchable()).toBe(true);
     });
+
     it("should be false when the field is not a string", () => {
-      const field = new Field({
-        isString: () => false,
+      const field = setup({
+        fields: [
+          createMockField({
+            id: FIELD_ID,
+            base_type: TYPE.Number,
+            semantic_type: TYPE.Number,
+          }),
+        ],
       });
+
       expect(field.isSearchable()).toBe(false);
     });
   });
 
   describe("fieldValues", () => {
     it("should return the values on a field instance", () => {
-      const values = [[1], [2]];
-      const field = new Field({
-        values,
+      const field = setup({
+        fields: [
+          createMockField({
+            id: FIELD_ID,
+            values: [[1], [2]],
+          }),
+        ],
       });
-      expect(field.fieldValues()).toEqual(values);
+
+      expect(field.fieldValues()).toEqual([[1], [2]]);
     });
 
     it("should wrap raw values in arrays to match the format of remapped values", () => {
-      const values = [1, 2];
-      const field = new Field({
-        values,
+      const field = setup({
+        fields: [
+          createMockField({
+            id: FIELD_ID,
+            values: [[1], [2]],
+          }),
+        ],
       });
+
       expect(field.fieldValues()).toEqual([[1], [2]]);
     });
   });
 
   describe("hasFieldValues", () => {
     it("should be true when a field has values", () => {
-      expect(
-        new Field({
-          values: [1],
-        }).hasFieldValues(),
-      ).toBe(true);
-    });
+      const field = setup({
+        fields: [
+          createMockField({
+            id: FIELD_ID,
+            values: [[1], [2]],
+          }),
+        ],
+      });
 
-    it("should be false when a field has no values", () => {
-      expect(
-        new Field({
-          values: [],
-        }).hasFieldValues(),
-      ).toBe(false);
-      expect(
-        new Field({
-          values: undefined,
-        }).hasFieldValues(),
-      ).toBe(false);
+      expect(field.hasFieldValues()).toBe(true);
     });
-  });
 
-  describe("getUniqueId", () => {
-    describe("when the `uniqueId` field exists on the instance", () => {
-      it("should return the `uniqueId`", () => {
-        const field = new Field({
-          uniqueId: "foo",
-        });
-        expect(field.getUniqueId()).toBe("foo");
+    it("should be false when a field has empty values", () => {
+      const field = setup({
+        fields: [
+          createMockField({
+            id: FIELD_ID,
+            values: [],
+          }),
+        ],
       });
-    });
 
-    describe("when the `uniqueId` field does not exist on the instance of a concrete Field", () => {
-      let field;
-      beforeEach(() => {
-        field = createMockConcreteField({
-          apiOpts: {
-            id: 1,
-            table_id: 2,
-          },
-        });
-      });
+      expect(field.hasFieldValues()).toBe(false);
+    });
 
-      it("should create a `uniqueId`", () => {
-        expect(field.getUniqueId()).toBe(1);
+    it("should be false when a field has no values", () => {
+      const field = setup({
+        fields: [
+          createMockField({
+            id: FIELD_ID,
+          }),
+        ],
       });
 
-      it("should set the `uniqueId` on the Field instance", () => {
-        field.getUniqueId();
-        expect(field.uniqueId).toBe(1);
-      });
+      expect(field.hasFieldValues()).toBe(false);
     });
+  });
 
-    describe("when the `uniqueId` field does not exist on the instance of a Field from a virtual card Table", () => {
-      let field;
-      beforeEach(() => {
-        field = createMockConcreteField({
-          apiOpts: {
-            id: 1,
-            table_id: "card__123",
-          },
+  describe("getUniqueId", () => {
+    describe("when the `uniqueId` field exists on the instance", () => {
+      it("should return the `uniqueId`", () => {
+        const field = setup({
+          fields: [
+            createMockField({
+              id: FIELD_ID,
+            }),
+          ],
         });
-      });
-
-      it("should create a `uniqueId`", () => {
-        expect(field.getUniqueId()).toBe("card__123:1");
-      });
 
-      it("should set the `uniqueId` on the Field instance", () => {
-        field.getUniqueId();
-        expect(field.uniqueId).toBe("card__123:1");
+        expect(field.getUniqueId()).toBe(1);
       });
     });
   });
diff --git a/frontend/src/metabase-lib/metadata/Metadata.ts b/frontend/src/metabase-lib/metadata/Metadata.ts
index 9023f331902bbe6273bc85e61cab004c6eee5789..9c2cad94892117fc1fbc72b77ec896cd1d73c271 100644
--- a/frontend/src/metabase-lib/metadata/Metadata.ts
+++ b/frontend/src/metabase-lib/metadata/Metadata.ts
@@ -94,7 +94,7 @@ class Metadata {
   }
 
   field(
-    fieldId: FieldId | FieldReference | undefined | null,
+    fieldId: FieldId | FieldReference | string | undefined | null,
     tableId?: TableId | undefined | null,
   ): Field | null {
     if (fieldId == null) {
diff --git a/frontend/src/metabase-lib/metadata/Metadata.unit.spec.ts b/frontend/src/metabase-lib/metadata/Metadata.unit.spec.ts
index 347d16ede7712a130a9910de1d88c0dafd59627b..4fe9a7fbcdbf309d2b315f850e5cdf6eaf0dfa65 100644
--- a/frontend/src/metabase-lib/metadata/Metadata.unit.spec.ts
+++ b/frontend/src/metabase-lib/metadata/Metadata.unit.spec.ts
@@ -1,249 +1,139 @@
-// eslint-disable-next-line @typescript-eslint/ban-ts-comment
-// @ts-nocheck
-import Metadata from "./Metadata";
-import Database from "./Database";
-import Table from "./Table";
-import Schema from "./Schema";
-import Segment from "./Segment";
-import Metric from "./Metric";
-import { createMockConcreteField } from "./mocks";
+import { createMockMetadata } from "__support__/metadata";
+import {
+  createMockDatabase,
+  createMockField,
+  createMockMetric,
+  createMockSegment,
+  createMockTable,
+} from "metabase-types/api/mocks";
 
 describe("Metadata", () => {
   describe("instantiation", () => {
     it("should create an instance of Metadata", () => {
-      expect(new Metadata()).toBeInstanceOf(Metadata);
-    });
-    it("should add `object` props to the instance", () => {
-      expect(
-        new Metadata({
-          foo: "bar",
-        }),
-      ).toHaveProperty("foo", "bar");
+      const metadata = createMockMetadata({});
+      expect(metadata).toBeDefined();
     });
   });
+
   describe("databasesList (deprecated)", () => {
-    let databases;
-    let databaseA;
-    let databaseB;
-    let databaseC;
-    beforeEach(() => {
-      databaseA = new Database({
-        id: 2,
-        name: "A",
-        is_saved_questions: true,
-      });
-      databaseB = new Database({
-        id: 3,
-        name: "B",
-      });
-      databaseC = new Database({
-        id: 1,
-        name: "C",
-      });
-      databases = {
-        1: databaseC,
-        2: databaseA,
-        3: databaseB,
-      };
+    const metadata = createMockMetadata({
+      databases: [
+        createMockDatabase({
+          id: 2,
+          name: "A",
+          is_saved_questions: true,
+        }),
+        createMockDatabase({
+          id: 3,
+          name: "B",
+        }),
+        createMockDatabase({
+          id: 1,
+          name: "C",
+        }),
+      ],
     });
+
     it("should return a sorted list of database objects found on the metadata instance", () => {
-      const metadata = new Metadata({
-        databases,
-      });
-      expect(metadata.databasesList()).toEqual([
-        databaseA,
-        databaseB,
-        databaseC,
+      const databases = metadata.databasesList();
+      expect(databases).toEqual([
+        metadata.database(2),
+        metadata.database(3),
+        metadata.database(1),
       ]);
     });
+
     it("should return all databases when the `savedQuestions` flag is true", () => {
-      const metadata = new Metadata({
-        databases,
-      });
-      expect(
-        metadata.databasesList({
-          savedQuestions: true,
-        }),
-      ).toEqual(metadata.databasesList());
+      const databases = metadata.databasesList({ savedQuestions: true });
+      expect(databases).toEqual([
+        metadata.database(2),
+        metadata.database(3),
+        metadata.database(1),
+      ]);
     });
+
     it("should exclude the 'is_saved_questions' db when the `savedQuestions` flag is false", () => {
-      const metadata = new Metadata({
-        databases,
-      });
-      expect(
-        metadata.databasesList({
-          savedQuestions: false,
-        }),
-      ).toEqual([databaseB, databaseC]);
+      const databases = metadata.databasesList({ savedQuestions: false });
+      expect(databases).toEqual([metadata.database(3), metadata.database(1)]);
     });
   });
+
   describe("tablesList (deprecated)", () => {
     it("should return a list of table objects found on the instance", () => {
-      const tableA = new Table({
-        id: 1,
-        name: "A",
-      });
-      const tableB = new Table({
-        id: 2,
-        name: "B",
-      });
-      const tables = {
-        1: tableA,
-        2: tableB,
-      };
-      const metadata = new Metadata({
-        tables,
+      const metadata = createMockMetadata({
+        tables: [createMockTable({ id: 1 }), createMockTable({ id: 2 })],
       });
-      expect(metadata.tablesList()).toEqual([tableA, tableB]);
+
+      const tables = metadata.tablesList();
+      expect(tables).toEqual([metadata.table(1), metadata.table(2)]);
     });
   });
   describe("metricsList (deprecated)", () => {
     it("should return a list of metric objects found on the instance", () => {
-      const metricA = new Metric({
-        id: 1,
-        name: "A",
-      });
-      const metricB = new Metric({
-        id: 2,
-        name: "B",
+      const metadata = createMockMetadata({
+        metrics: [createMockMetric({ id: 1 }), createMockMetric({ id: 2 })],
       });
-      const metrics = {
-        1: metricA,
-        2: metricB,
-      };
-      const metadata = new Metadata({
-        metrics,
-      });
-      expect(metadata.metricsList()).toEqual([metricA, metricB]);
+
+      const metrics = metadata.metricsList();
+      expect(metrics).toEqual([metadata.metric(1), metadata.metric(2)]);
     });
   });
   describe("segmentsList (deprecated)", () => {
     it("should return a list of segment objects found on the instance", () => {
-      const segmentA = new Segment({
-        id: 1,
-        name: "A",
+      const metadata = createMockMetadata({
+        segments: [createMockSegment({ id: 1 }), createMockSegment({ id: 2 })],
       });
-      const segmentB = new Segment({
-        id: 2,
-        name: "B",
-      });
-      const segments = {
-        1: segmentA,
-        2: segmentB,
-      };
-      const metadata = new Metadata({
-        segments,
-      });
-      expect(metadata.segmentsList()).toEqual([segmentA, segmentB]);
-    });
-  });
 
-  [
-    ["segment", obj => new Segment(obj)],
-    ["metric", obj => new Metric(obj)],
-    ["database", obj => new Database(obj)],
-    ["schema", obj => new Schema(obj)],
-    ["table", obj => new Table(obj)],
-  ].forEach(([fnName, instantiate]) => {
-    describe(fnName, () => {
-      let instanceA;
-      let instanceB;
-      let metadata;
-      beforeEach(() => {
-        instanceA = instantiate({
-          id: 1,
-          name: "A",
-        });
-        instanceB = instantiate({
-          id: 2,
-          name: "B",
-        });
-        const instances = {
-          1: instanceA,
-          2: instanceB,
-        };
-        metadata = new Metadata({
-          [`${fnName}s`]: instances,
-        });
-      });
-      it(`should retun the ${fnName} with the given id`, () => {
-        expect(metadata[fnName](1)).toBe(instanceA);
-        expect(metadata[fnName](2)).toBe(instanceB);
-      });
-      it("should return null when the id matches nothing", () => {
-        expect(metadata[fnName](3)).toBeNull();
-      });
-      it("should return null when the id is nil", () => {
-        expect(metadata[fnName]()).toBeNull();
-      });
+      const segments = metadata.segmentsList();
+      expect(segments).toEqual([metadata.segment(1), metadata.segment(2)]);
     });
   });
 
   describe("`field`", () => {
     it("should return null when given a nil fieldId arg", () => {
-      const metadata = new Metadata({
-        fields: {},
-      });
-      expect(metadata.field()).toBeNull();
+      const metadata = createMockMetadata({});
       expect(metadata.field(null)).toBeNull();
     });
 
     describe("when given a fieldId and no tableId", () => {
       it("should return null when there is no matching field", () => {
-        const metadata = new Metadata({
-          fields: {},
-        });
+        const metadata = createMockMetadata({});
         expect(metadata.field(1)).toBeNull();
       });
 
       it("should return the matching Field instance", () => {
-        const field = createMockConcreteField({ apiOpts: { id: 1 } });
-        const uniqueId = field.getUniqueId();
-        const metadata = new Metadata({
-          fields: {
-            [uniqueId]: field,
-          },
+        const metadata = createMockMetadata({
+          fields: [createMockField({ id: 1 })],
         });
 
-        expect(metadata.field(1)).toBe(field);
+        expect(metadata.field(1)).toBeDefined();
       });
     });
 
     describe("when given a fieldId and a concrete tableId", () => {
       it("should ignore the tableId arg because these fields are stored using the field's id", () => {
-        const field = createMockConcreteField({
-          apiOpts: { id: 1, table_id: 1 },
-        });
-        const uniqueId = field.getUniqueId();
-        const metadata = new Metadata({
-          fields: {
-            [uniqueId]: field,
-          },
+        const metadata = createMockMetadata({
+          fields: [createMockField({ id: 1, table_id: 1 })],
         });
 
+        const field = metadata.field(1);
+        expect(field).toBeDefined();
         expect(metadata.field(1, 1)).toBe(field);
-        // to prove the point that the `tableId` is ignore in this scenario
+        // to prove the point that the `tableId` is ignored in this scenario
         expect(metadata.field(1, 2)).toBe(field);
-        expect(metadata.field(1)).toBe(field);
       });
     });
 
     describe("when given a fieldId and a virtual card tableId", () => {
       it("should return the matching Field instance, stored using the field's `uniqueId`", () => {
-        const field = createMockConcreteField({
-          apiOpts: { id: 1, table_id: "card__123" },
-        });
-        const uniqueId = field.getUniqueId();
-        const metadata = new Metadata({
-          fields: {
-            [uniqueId]: field,
-          },
+        const metadata = createMockMetadata({
+          fields: [createMockField({ id: 1, table_id: "card__123" })],
         });
 
-        expect(metadata.field(1, "card__123")).toBe(field);
+        const field = metadata.field(1, "card__123");
+        expect(field).toBeDefined();
         expect(metadata.field("card__123:1")).toBe(field);
-
-        expect(metadata.field(1)).not.toBe(field);
+        expect(metadata.field(1)).toBeNull();
       });
     });
   });
diff --git a/frontend/src/metabase-lib/metadata/Schema.unit.spec.ts b/frontend/src/metabase-lib/metadata/Schema.unit.spec.ts
index bc6845e8e87fd82ca0caddc08a64aec53f191a60..5ec3ed7edd05ced1a8d858a7287e03c686ef2cdd 100644
--- a/frontend/src/metabase-lib/metadata/Schema.unit.spec.ts
+++ b/frontend/src/metabase-lib/metadata/Schema.unit.spec.ts
@@ -1,27 +1,29 @@
-import Schema from "./Schema";
+import { Table } from "metabase-types/api";
+import { createMockTable } from "metabase-types/api/mocks";
+import { createMockMetadata } from "__support__/metadata";
+
+const TEST_TABLE = createMockTable({
+  schema: "foo_bar",
+});
+
+interface SetupOpts {
+  table?: Table;
+}
+
+const setup = ({ table = TEST_TABLE }: SetupOpts = {}) => {
+  const metadata = createMockMetadata({ tables: [table] });
+  const instance = metadata.table(table.id)?.schema;
+  if (!instance) {
+    throw new TypeError();
+  }
+
+  return instance;
+};
 
 describe("Schema", () => {
-  describe("instantiation", () => {
-    it("should create an instance of Schema", () => {
-      expect(new Schema({ id: "1:public", name: "public" })).toBeInstanceOf(
-        Schema,
-      );
-    });
-    it("should add `object` props to the instance", () => {
-      expect(
-        new Schema({
-          id: "1:public",
-          name: "public",
-        }),
-      ).toHaveProperty("name", "public");
-    });
-  });
   describe("displayName", () => {
     it("should return a formatted `name` string", () => {
-      const schema = new Schema({
-        id: "name: public",
-        name: "foo_bar",
-      });
+      const schema = setup();
       expect(schema.displayName()).toBe("Foo Bar");
     });
   });
diff --git a/frontend/src/metabase-lib/metadata/Segment.unit.spec.ts b/frontend/src/metabase-lib/metadata/Segment.unit.spec.ts
index 56332969d54897f4937ffac04ec6b79b8a700af2..d84c64b6e2cbcedb552a18c1c78949ee1277b42e 100644
--- a/frontend/src/metabase-lib/metadata/Segment.unit.spec.ts
+++ b/frontend/src/metabase-lib/metadata/Segment.unit.spec.ts
@@ -1,45 +1,75 @@
-// eslint-disable-next-line @typescript-eslint/ban-ts-comment
-// @ts-nocheck
-import Segment from "./Segment";
+import { Segment } from "metabase-types/api";
+import { createMockSegment } from "metabase-types/api/mocks";
+import { createMockMetadata } from "__support__/metadata";
+
+interface SetupOpts {
+  segment?: Segment;
+}
+
+const setup = ({ segment = createMockSegment() }: SetupOpts = {}) => {
+  const metadata = createMockMetadata({
+    segments: [segment],
+  });
+
+  const instance = metadata.segment(segment.id);
+  if (!instance) {
+    throw new TypeError();
+  }
+
+  return instance;
+};
 
 describe("Segment", () => {
   describe("instantiation", () => {
     it("should create an instance of Segment", () => {
-      expect(new Segment()).toBeInstanceOf(Segment);
+      const segment = setup();
+      expect(segment).toBeDefined();
     });
   });
+
   describe("displayName", () => {
     it("should return the `name` property found on the instance", () => {
-      expect(
-        new Segment({
+      const segment = setup({
+        segment: createMockSegment({
           name: "foo",
-        }).displayName(),
-      ).toBe("foo");
+        }),
+      });
+
+      expect(segment.displayName()).toBe("foo");
     });
   });
+
   describe("filterClause", () => {
     it("should return a filter clause", () => {
-      expect(
-        new Segment({
+      const segment = setup({
+        segment: createMockSegment({
           id: 123,
-        }).filterClause(),
-      ).toEqual(["segment", 123]);
+        }),
+      });
+
+      expect(segment.filterClause()).toEqual(["segment", 123]);
     });
   });
+
   describe("isActive", () => {
     it("should return true if the segment is not archived", () => {
-      expect(
-        new Segment({
+      const segment = setup({
+        segment: createMockSegment({
           archived: false,
-        }).isActive(),
-      ).toBe(true);
+        }),
+      });
+
+      expect(segment.isActive()).toBe(true);
     });
+
     it("should return false if the segment is archived", () => {
-      expect(
-        new Segment({
+      const segment = setup({
+        segment: createMockSegment({
           archived: true,
-        }).isActive(),
-      ).toBe(false);
+        }),
+      });
+
+      expect(segment.isActive()).toBe(false);
     });
   });
 });
diff --git a/frontend/src/metabase-lib/metadata/utils/fields.ts b/frontend/src/metabase-lib/metadata/utils/fields.ts
index 6b28120d460e2f351fe12f01551900df733eb760..8e4abb907a36524538a260865cf7e7e57736358e 100644
--- a/frontend/src/metabase-lib/metadata/utils/fields.ts
+++ b/frontend/src/metabase-lib/metadata/utils/fields.ts
@@ -1,3 +1,4 @@
+import { FieldId, FieldReference, TableId } from "metabase-types/api";
 import { isVirtualCardId } from "metabase-lib/metadata/utils/saved-questions";
 import {
   BOOLEAN,
@@ -11,7 +12,6 @@ import {
   TEMPORAL,
 } from "metabase-lib/types/constants";
 import { getFieldType } from "metabase-lib/types/utils/isa";
-import type Field from "../Field";
 
 const ICON_MAPPING: Record<string, string> = {
   [TEMPORAL]: "calendar",
@@ -33,11 +33,16 @@ export function getIconForField(fieldOrColumn: any) {
   return type && ICON_MAPPING[type] ? ICON_MAPPING[type] : "unknown";
 }
 
-export function getUniqueFieldId(
-  field: Pick<Field, "id" | "name" | "table_id">,
-): number | string {
-  const { table_id } = field;
-  const fieldIdentifier = getFieldIdentifier(field);
+export function getUniqueFieldId({
+  id,
+  name,
+  table_id,
+}: {
+  id: FieldId | FieldReference | string;
+  name?: string | undefined | null;
+  table_id?: TableId | undefined | null;
+}): number | string {
+  const fieldIdentifier = getFieldIdentifier({ id, name });
 
   if (isVirtualCardId(table_id)) {
     return `${table_id}:${fieldIdentifier}`;
@@ -46,13 +51,16 @@ export function getUniqueFieldId(
   return fieldIdentifier;
 }
 
-function getFieldIdentifier(
-  field: Pick<Field, "id" | "name">,
-): number | string {
-  const { id, name } = field;
+function getFieldIdentifier({
+  id,
+  name,
+}: {
+  id: FieldId | FieldReference | string;
+  name?: string | undefined | null;
+}): number | string {
   if (Array.isArray(id)) {
     return id[1];
   }
 
-  return id || name;
+  return id ?? name;
 }
diff --git a/frontend/src/metabase-lib/metadata/utils/models.ts b/frontend/src/metabase-lib/metadata/utils/models.ts
index 089cd03cc566fba76d037c02a67ef3192c767e06..e7bd5b572c0250f8ef5ff665c1c8f9d75c4c1f12 100644
--- a/frontend/src/metabase-lib/metadata/utils/models.ts
+++ b/frontend/src/metabase-lib/metadata/utils/models.ts
@@ -15,7 +15,7 @@ import { isSameField } from "metabase-lib/queries/utils/field-ref";
 import { isStructured } from "metabase-lib/queries/utils";
 
 type FieldMetadata = {
-  id?: number;
+  id?: number | string;
   name: string;
   display_name: string;
   description?: string | null;
diff --git a/frontend/src/metabase-types/api/field.ts b/frontend/src/metabase-types/api/field.ts
index 6030e4867a5c854152f5310aba25c55f91563290..c67e159824f757cc4d9f1d141bf1f6b7b6803f1b 100644
--- a/frontend/src/metabase-types/api/field.ts
+++ b/frontend/src/metabase-types/api/field.ts
@@ -55,6 +55,7 @@ export type FieldValuesType = "list" | "search" | "none";
 
 export type FieldDimension = {
   name: string;
+  human_readable_field_id?: FieldId;
   human_readable_field?: Field;
 };
 
@@ -86,11 +87,13 @@ export interface ConcreteField {
   fk_target_field_id: FieldId | null;
   target?: Field;
   values?: FieldValue[];
+  remappings?: FieldValue[];
   settings?: FieldFormattingSettings;
 
   dimensions?: FieldDimension[];
   default_dimension_option?: FieldDimensionOption;
   dimension_options?: FieldDimensionOption[];
+  name_field?: Field;
 
   max_value?: number;
   min_value?: number;
diff --git a/frontend/src/metabase-types/api/schema.ts b/frontend/src/metabase-types/api/schema.ts
index d4e99d923b1f6364a94552598aed2ae807d7ea87..44fd91b80f34c57c6055744b8369874a7654f2d6 100644
--- a/frontend/src/metabase-types/api/schema.ts
+++ b/frontend/src/metabase-types/api/schema.ts
@@ -41,6 +41,7 @@ export interface NormalizedTable
   segments?: SegmentId[];
   metrics?: MetricId[];
   schema?: SchemaId;
+  schema_name?: string;
 }
 
 export interface NormalizedForeignKey
diff --git a/frontend/src/metabase-types/api/table.ts b/frontend/src/metabase-types/api/table.ts
index cc8f9c6f1269aea0b542998040aaffacd4c001fb..7191a38751216003be5858e02240b87eb6fff43d 100644
--- a/frontend/src/metabase-types/api/table.ts
+++ b/frontend/src/metabase-types/api/table.ts
@@ -30,7 +30,6 @@ export interface Table {
   db_id: DatabaseId;
   db?: Database;
 
-  schema_name?: string;
   schema: string;
 
   fks?: ForeignKey[];
diff --git a/frontend/test/metabase-lib/lib/queries/StructuredQuery-nesting.unit.spec.js b/frontend/test/metabase-lib/lib/queries/StructuredQuery-nesting.unit.spec.js
index ffc3df7be3b47c04ecc8d6716746deb0ef2e2fcf..4ae2df0e6e07bc7af30a071e38db27e690d34619 100644
--- a/frontend/test/metabase-lib/lib/queries/StructuredQuery-nesting.unit.spec.js
+++ b/frontend/test/metabase-lib/lib/queries/StructuredQuery-nesting.unit.spec.js
@@ -1,23 +1,32 @@
-import { createMockMetadata } from "__support__/metadata";
+import { createMockField, createMockTable } from "metabase-types/api/mocks";
 import {
+  createOrdersTable,
+  createProductsTable,
   createSampleDatabase,
   ORDERS,
   ORDERS_ID,
-  PRODUCTS_ID,
   PEOPLE_ID,
+  PRODUCTS_ID,
 } from "metabase-types/api/mocks/presets";
+import { createMockMetadata } from "__support__/metadata";
 
-const metadata = createMockMetadata({
-  databases: [createSampleDatabase()],
-});
+const setup = ({ tables = [] } = {}) => {
+  const metadata = createMockMetadata({
+    databases: [createSampleDatabase()],
+    tables,
+  });
 
-const ordersTable = metadata.table(ORDERS_ID);
-const productsTable = metadata.table(PRODUCTS_ID);
-const peopleTable = metadata.table(PEOPLE_ID);
+  return {
+    ordersTable: metadata.table(ORDERS_ID),
+    productsTable: metadata.table(PRODUCTS_ID),
+    peopleTable: metadata.table(PEOPLE_ID),
+  };
+};
 
 describe("StructuredQuery nesting", () => {
   describe("nest", () => {
     it("should nest correctly", () => {
+      const { ordersTable } = setup();
       const q = ordersTable.query();
       expect(q.query()).toEqual({ "source-table": ORDERS_ID });
       expect(q.nest().query()).toEqual({
@@ -26,6 +35,7 @@ describe("StructuredQuery nesting", () => {
     });
 
     it("should be able to modify the outer question", () => {
+      const { ordersTable } = setup();
       const q = ordersTable.query();
       expect(
         q
@@ -39,6 +49,7 @@ describe("StructuredQuery nesting", () => {
     });
 
     it("should be able to modify the source question", () => {
+      const { ordersTable } = setup();
       const q = ordersTable.query();
       expect(
         q
@@ -56,6 +67,7 @@ describe("StructuredQuery nesting", () => {
     });
 
     it("should return a table with correct dimensions", () => {
+      const { ordersTable } = setup();
       const q = ordersTable
         .query()
         .aggregate(["count"])
@@ -74,6 +86,7 @@ describe("StructuredQuery nesting", () => {
 
   describe("topLevelFilters", () => {
     it("should return filters for the last two stages", () => {
+      const { ordersTable } = setup();
       const q = ordersTable
         .query()
         .aggregate(["count"])
@@ -93,12 +106,14 @@ describe("StructuredQuery nesting", () => {
 
   describe("topLevelQuery", () => {
     it("should return the query if it's summarized", () => {
+      const { ordersTable } = setup();
       const q = ordersTable.query();
       expect(q.topLevelQuery().query()).toEqual({
         "source-table": ORDERS_ID,
       });
     });
     it("should return the query if it's not summarized", () => {
+      const { ordersTable } = setup();
       const q = ordersTable.query().aggregate(["count"]);
       expect(q.topLevelQuery().query()).toEqual({
         "source-table": ORDERS_ID,
@@ -106,12 +121,14 @@ describe("StructuredQuery nesting", () => {
       });
     });
     it("should return last stage if none are summarized", () => {
+      const { ordersTable } = setup();
       const q = ordersTable.query().nest();
       expect(q.topLevelQuery().query()).toEqual({
         "source-query": { "source-table": ORDERS_ID },
       });
     });
     it("should return last summarized stage if any is summarized", () => {
+      const { ordersTable } = setup();
       const q = ordersTable.query().aggregate(["count"]).nest();
       expect(q.topLevelQuery().query()).toEqual({
         "source-table": ORDERS_ID,
@@ -122,6 +139,7 @@ describe("StructuredQuery nesting", () => {
 
   describe("topLevelDimension", () => {
     it("should return same dimension if not nested", () => {
+      const { ordersTable } = setup();
       const q = ordersTable.query();
       const d = q.topLevelDimension(
         q.parseFieldReference(["field", ORDERS.TOTAL, null]),
@@ -129,6 +147,7 @@ describe("StructuredQuery nesting", () => {
       expect(d.mbql()).toEqual(["field", ORDERS.TOTAL, null]);
     });
     it("should return underlying dimension for a nested query", () => {
+      const { ordersTable } = setup();
       const q = ordersTable
         .query()
         .aggregate(["count"])
@@ -146,72 +165,40 @@ describe("StructuredQuery nesting", () => {
   });
 
   describe("model question", () => {
-    let dataset;
-    let virtualCardTable;
-    beforeEach(() => {
-      const question = ordersTable.question();
-      dataset = question.setId(123).setDataset(true);
-
-      // create a virtual table for the card
-      // that contains fields from both Orders and Products tables
-      // to imitate an explicit join of Products to Orders
-      virtualCardTable = ordersTable.clone();
-      virtualCardTable.id = `card__123`;
-      virtualCardTable.fields = virtualCardTable.fields
-        .map(f =>
-          f.clone({
-            table_id: `card__123`,
-            uniqueId: `card__123:${f.id}`,
-          }),
-        )
-        .concat(
-          productsTable.fields.map(f => {
-            const field = f.clone({
-              table_id: `card__123`,
-              uniqueId: `card__123:${f.id}`,
-            });
+    it("should not include implicit join dimensions when the underyling question has an explicit join", () => {
+      const fields = [
+        ...createOrdersTable().fields,
+        ...createProductsTable().fields,
+      ];
 
-            return field;
+      const { ordersTable, productsTable, peopleTable } = setup({
+        tables: [
+          createMockTable({
+            id: "card__1",
+            fields: fields.map(field =>
+              createMockField({ ...field, table_id: "card__1" }),
+            ),
           }),
-        );
-
-      // add instances to the `metadata` instance
-      metadata.questions[dataset.id()] = dataset;
-      metadata.tables[virtualCardTable.id] = virtualCardTable;
-      virtualCardTable.fields.forEach(f => {
-        metadata.fields[f.uniqueId] = f;
+        ],
       });
-    });
 
-    it("should not include implicit join dimensions when the underyling question has an explicit join", () => {
+      const metadata = ordersTable.metadata;
+      const question = ordersTable.question();
+      const dataset = question.setId(1).setDataset(true);
       const nestedDatasetQuery = dataset.composeDataset().query();
       expect(
         // get a list of all dimension options for the nested query
         nestedDatasetQuery
           .dimensionOptions()
           .all()
-          .map(d => d.field().getPlainObject()),
+          .map(d => d.field()),
       ).toEqual([
         // Order fields
-        ...ordersTable.fields.map(f =>
-          f
-            .clone({
-              table_id: `card__123`,
-              uniqueId: `card__123:${f.id}`,
-            })
-            .getPlainObject(),
-        ),
+        ...ordersTable.fields.map(({ id }) => metadata.field(id, "card__1")),
         // Product fields from the explicit join
-        ...productsTable.fields.map(f =>
-          f
-            .clone({
-              table_id: `card__123`,
-              uniqueId: `card__123:${f.id}`,
-            })
-            .getPlainObject(),
-        ),
+        ...productsTable.fields.map(({ id }) => metadata.field(id, "card__1")),
         // People fields from the implicit join
-        ...peopleTable.fields.map(f => f.getPlainObject()),
+        ...peopleTable.fields,
       ]);
     });
   });