diff --git a/frontend/src/metabase-lib/metadata/Schema.ts b/frontend/src/metabase-lib/metadata/Schema.ts
index 0bd70db35acbf8fda4d1878e9325aaa776411dad..543dddbcff6120549e92a5a48ee95a0e159f2fed 100644
--- a/frontend/src/metabase-lib/metadata/Schema.ts
+++ b/frontend/src/metabase-lib/metadata/Schema.ts
@@ -1,20 +1,30 @@
-// eslint-disable-next-line @typescript-eslint/ban-ts-comment
-// @ts-nocheck
-import { titleize, humanize } from "metabase/lib/formatting";
-import Base from "./Base";
+import { humanize, titleize } from "metabase/lib/formatting";
+import { NormalizedSchema } from "metabase-types/api";
 import type Metadata from "./Metadata";
 import type Database from "./Database";
 import type Table from "./Table";
-/**
- * Wrapper class for a {@link Database} schema. Contains {@link Table}s.
- */
 
-export default class Schema extends Base {
-  id: string;
-  name: string;
-  database: Database;
-  tables: Table[];
-  metadata: Metadata;
+export default class Schema {
+  private readonly schema: NormalizedSchema;
+  metadata?: Metadata;
+  database?: Database;
+  tables: Table[] = [];
+
+  constructor(schema: NormalizedSchema) {
+    this.schema = schema;
+  }
+
+  get id() {
+    return this.schema.id;
+  }
+
+  get name() {
+    return this.schema.name;
+  }
+
+  getPlainObject() {
+    return this.schema;
+  }
 
   displayName() {
     return this.name ? titleize(humanize(this.name)) : null;
@@ -23,18 +33,4 @@ export default class Schema extends Base {
   getTables() {
     return this.tables;
   }
-
-  /**
-   * @private
-   * @param {string} name
-   * @param {Database} database
-   * @param {Table[]} tables
-   */
-
-  /* istanbul ignore next */
-  _constructor(name, database, tables) {
-    this.name = name;
-    this.database = database;
-    this.tables = tables;
-  }
 }
diff --git a/frontend/src/metabase-lib/metadata/Schema.unit.spec.ts b/frontend/src/metabase-lib/metadata/Schema.unit.spec.ts
index e7120a4c7581c9cd8018bbf793d73a101ef8c0c4..bc6845e8e87fd82ca0caddc08a64aec53f191a60 100644
--- a/frontend/src/metabase-lib/metadata/Schema.unit.spec.ts
+++ b/frontend/src/metabase-lib/metadata/Schema.unit.spec.ts
@@ -1,24 +1,25 @@
-// eslint-disable-next-line @typescript-eslint/ban-ts-comment
-// @ts-nocheck
 import Schema from "./Schema";
-import Base from "./Base";
+
 describe("Schema", () => {
   describe("instantiation", () => {
     it("should create an instance of Schema", () => {
-      expect(new Schema()).toBeInstanceOf(Schema);
+      expect(new Schema({ id: "1:public", name: "public" })).toBeInstanceOf(
+        Schema,
+      );
     });
-    it("should add `object` props to the instance (because it extends Base)", () => {
-      expect(new Schema()).toBeInstanceOf(Base);
+    it("should add `object` props to the instance", () => {
       expect(
         new Schema({
-          foo: "bar",
+          id: "1:public",
+          name: "public",
         }),
-      ).toHaveProperty("foo", "bar");
+      ).toHaveProperty("name", "public");
     });
   });
   describe("displayName", () => {
     it("should return a formatted `name` string", () => {
       const schema = new Schema({
+        id: "name: public",
         name: "foo_bar",
       });
       expect(schema.displayName()).toBe("Foo Bar");
diff --git a/frontend/src/metabase/admin/permissions/utils/data-entity-id.ts b/frontend/src/metabase/admin/permissions/utils/data-entity-id.ts
index 8b877f0c33b5603636c0dc657685adc11cb1f741..6a8ec4622d790188ec0be67fdc2015958cab1086 100644
--- a/frontend/src/metabase/admin/permissions/utils/data-entity-id.ts
+++ b/frontend/src/metabase/admin/permissions/utils/data-entity-id.ts
@@ -1,3 +1,4 @@
+import { checkNotNull } from "metabase/core/utils/types";
 import type { ConcreteTableId } from "metabase-types/api";
 import type Database from "metabase-lib/metadata/Database";
 import type Schema from "metabase-lib/metadata/Schema";
@@ -9,7 +10,7 @@ export const getDatabaseEntityId = (databaseEntity: Database) => ({
 });
 
 export const getSchemaEntityId = (schemaEntity: Schema) => ({
-  databaseId: schemaEntity.database.id,
+  databaseId: checkNotNull(schemaEntity.database).id,
   schemaName: schemaEntity.name,
 });
 
diff --git a/frontend/src/metabase/query_builder/components/DataSelector/DataSelectorDatabaseSchemaPicker/DataSelectorDatabaseSchemaPicker.tsx b/frontend/src/metabase/query_builder/components/DataSelector/DataSelectorDatabaseSchemaPicker/DataSelectorDatabaseSchemaPicker.tsx
index 954f214eb3500133dd23e331c054403bc847a564..6825b0ec6af79a413db971465646605d7c9e664a 100644
--- a/frontend/src/metabase/query_builder/components/DataSelector/DataSelectorDatabaseSchemaPicker/DataSelectorDatabaseSchemaPicker.tsx
+++ b/frontend/src/metabase/query_builder/components/DataSelector/DataSelectorDatabaseSchemaPicker/DataSelectorDatabaseSchemaPicker.tsx
@@ -107,7 +107,7 @@ const DataSelectorDatabaseSchemaPicker = ({
   }
 
   let openSection = selectedSchema
-    ? databases.findIndex(db => db.id === selectedSchema.database.id)
+    ? databases.findIndex(db => db.id === selectedSchema.database?.id)
     : selectedDatabase
     ? databases.findIndex(db => db.id === selectedDatabase.id)
     : -1;
diff --git a/frontend/src/metabase/selectors/metadata.ts b/frontend/src/metabase/selectors/metadata.ts
index 837fb501741c1f54891ee1a429cb021d0c1e4f0c..421754b23823c8721630b27183368bbda2619f88 100644
--- a/frontend/src/metabase/selectors/metadata.ts
+++ b/frontend/src/metabase/selectors/metadata.ts
@@ -127,10 +127,8 @@ export const getMetadata: (
       );
     });
     // schema
-    hydrate(
-      metadata.schemas,
-      "database",
-      schema => metadata.database(schema.database) as Database,
+    hydrate(metadata.schemas, "database", schema =>
+      metadata.database(schema.getPlainObject().database),
     );
 
     // table
@@ -151,10 +149,11 @@ export const getMetadata: (
       );
     });
 
-    hydrate(metadata.schemas, "tables", schema =>
-      schema.tables
+    hydrate(metadata.schemas, "tables", schema => {
+      const tableIds = schema.getPlainObject().tables;
+      return tableIds
         ? // use the schema tables if they exist
-          schema.tables.map(table => metadata.table(table))
+          tableIds.map(table => metadata.table(table))
         : schema.database && schema.database.tables.length > 0
         ? // if the schema has a database with tables, use those
           schema.database.tables.filter(
@@ -163,8 +162,8 @@ export const getMetadata: (
         : // otherwise use any loaded tables that match the schema id
           Object.values(metadata.tables).filter(
             table => table.schema && table.schema.id === schema.id,
-          ),
-    );
+          );
+    });
 
     // segments
     hydrate(