diff --git a/e2e/test/scenarios/dashboard-filters/temporal-unit-parameters.cy.spec.js b/e2e/test/scenarios/dashboard-filters/temporal-unit-parameters.cy.spec.js
index ec8585e09b3e7539624761cb42e1771ba49a3507..17faabcf41923a9e3f126bca2b00d4fba90775ce 100644
--- a/e2e/test/scenarios/dashboard-filters/temporal-unit-parameters.cy.spec.js
+++ b/e2e/test/scenarios/dashboard-filters/temporal-unit-parameters.cy.spec.js
@@ -387,9 +387,9 @@ describe("scenarios > dashboard > temporal unit parameters", () => {
         .should("contain.text", "Started from")
         .should("contain.text", multiBreakoutQuestionDetails.name);
       queryBuilderMain().within(() => {
-        cy.findByText("Product → Created At: Week").should("be.visible");
-        cy.findByText("2022").should("be.visible");
-        cy.findByText("2023").should("be.visible");
+        cy.findByText("Created At: Year").should("be.visible");
+        cy.findByText("April 24, 2022").should("be.visible");
+        cy.findByText("May 1, 2022").should("be.visible");
       });
     });
 
diff --git a/frontend/src/metabase-lib/v1/queries/utils/column-key.ts b/frontend/src/metabase-lib/v1/queries/utils/column-key.ts
new file mode 100644
index 0000000000000000000000000000000000000000..6fbe550f364cc4a0c2160fb146b23e0eab5dca6f
--- /dev/null
+++ b/frontend/src/metabase-lib/v1/queries/utils/column-key.ts
@@ -0,0 +1,81 @@
+import {
+  createFieldReference,
+  getBaseDimensionReference,
+  getNormalizedDimensionReference,
+  hasStringFieldName,
+  isAggregationReference,
+  isExpressionReference,
+  isFieldReference,
+  isValidDimensionReference,
+} from "metabase-lib/v1/references";
+import type {
+  ColumnSettings,
+  DatasetColumn,
+  VisualizationSettings,
+} from "metabase-types/api";
+
+export type DatasetColumnReference = Pick<DatasetColumn, "name" | "field_ref">;
+
+export const getColumnKey = (column: DatasetColumnReference) => {
+  return JSON.stringify(["name", column.name]);
+};
+
+export const getLegacyColumnKey = (column: DatasetColumnReference) => {
+  let fieldRef = column.field_ref;
+
+  if (!fieldRef) {
+    fieldRef = createFieldReference(column.name);
+  }
+
+  if (!isValidDimensionReference(fieldRef)) {
+    console.warn("Unknown field_ref", fieldRef);
+    return JSON.stringify(fieldRef);
+  }
+
+  fieldRef = getNormalizedDimensionReference(fieldRef);
+
+  if (
+    isFieldReference(fieldRef) ||
+    isExpressionReference(fieldRef) ||
+    isAggregationReference(fieldRef)
+  ) {
+    fieldRef = getBaseDimensionReference(fieldRef);
+  }
+
+  const isLegacyRef =
+    (isFieldReference(fieldRef) && hasStringFieldName(fieldRef)) ||
+    isAggregationReference(fieldRef);
+
+  return JSON.stringify(
+    isLegacyRef ? ["name", column.name] : ["ref", fieldRef],
+  );
+};
+
+export const getColumnNameFromKey = (key: string) => {
+  try {
+    const [tag, name] = JSON.parse(key);
+    return tag === "name" ? name : undefined;
+  } catch {
+    return undefined;
+  }
+};
+
+export const getColumnSettings = (
+  settings: VisualizationSettings | null | undefined,
+  column: DatasetColumnReference,
+) => {
+  return getObjectColumnSettings(settings?.column_settings, column);
+};
+
+// Gets the corresponding viz settings for the column. We check for both
+// legacy and modern keys because not all viz settings have been migrated.
+// To be extra safe and maintain backward compatibility, we check for the
+// legacy key first.
+export const getObjectColumnSettings = (
+  settings: Record<string, ColumnSettings> | null | undefined,
+  column: DatasetColumnReference,
+) => {
+  return (
+    settings?.[getLegacyColumnKey(column)] ?? settings?.[getColumnKey(column)]
+  );
+};
diff --git a/frontend/src/metabase-lib/v1/queries/utils/column-key.unit.spec.ts b/frontend/src/metabase-lib/v1/queries/utils/column-key.unit.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ff4594ef7829c362c7b8f3aad5e6acad49b11715
--- /dev/null
+++ b/frontend/src/metabase-lib/v1/queries/utils/column-key.unit.spec.ts
@@ -0,0 +1,208 @@
+import {
+  getColumnKey,
+  getColumnNameFromKey,
+  getColumnSettings,
+  getLegacyColumnKey,
+  getObjectColumnSettings,
+} from "metabase-lib/v1/queries/utils/column-key";
+import type { DatasetColumn } from "metabase-types/api";
+import {
+  createMockColumn,
+  createMockVisualizationSettings,
+} from "metabase-types/api/mocks";
+
+type TestCase = {
+  title: string;
+  column: DatasetColumn;
+  expectedKey: string;
+};
+
+describe("getColumnKey", () => {
+  it.each<TestCase>([
+    {
+      title: "id-based field ref",
+      column: createMockColumn({ name: "foo", field_ref: ["field", 1, null] }),
+      expectedKey: JSON.stringify(["name", "foo"]),
+    },
+    {
+      title: "name-based field ref",
+      column: createMockColumn({
+        name: "foo",
+        field_ref: ["field", "foo", { "base-type": "type/Text" }],
+      }),
+      expectedKey: JSON.stringify(["name", "foo"]),
+    },
+  ])("should create a name-based key: $title", ({ column, expectedKey }) => {
+    expect(getColumnKey(column)).toEqual(expectedKey);
+  });
+});
+
+describe("getLegacyColumnKey", () => {
+  it.each<TestCase>([
+    {
+      title: "id-based field ref",
+      column: createMockColumn({ name: "foo", field_ref: ["field", 1, null] }),
+      expectedKey: JSON.stringify(["ref", ["field", 1, null]]),
+    },
+    {
+      title: "explicitly joined column",
+      column: createMockColumn({
+        name: "foo",
+        field_ref: ["field", 1, { "join-alias": "x" }],
+      }),
+      expectedKey: JSON.stringify(["ref", ["field", 1, { "join-alias": "x" }]]),
+    },
+    {
+      title: "implicitly joined column",
+      column: createMockColumn({
+        name: "foo",
+        field_ref: ["field", 1, { "source-field": 2 }],
+      }),
+      expectedKey: JSON.stringify(["ref", ["field", 1, { "source-field": 2 }]]),
+    },
+    {
+      title: "temporal-unit is removed from the key",
+      column: createMockColumn({
+        name: "foo",
+        field_ref: ["field", 1, { "temporal-unit": "minute" }],
+      }),
+      expectedKey: JSON.stringify(["ref", ["field", 1, null]]),
+    },
+    {
+      title: "binning is removed from key",
+      column: createMockColumn({
+        name: "foo",
+        field_ref: [
+          "field",
+          1,
+          {
+            "base-type": "type/Integer",
+            binning: { strategy: "num-bins", "num-bins": 10 },
+          },
+        ],
+      }),
+      expectedKey: JSON.stringify([
+        "ref",
+        ["field", 1, { "base-type": "type/Integer" }],
+      ]),
+    },
+    {
+      title: "expression",
+      column: createMockColumn({
+        name: "foo",
+        field_ref: ["expression", "foo"],
+      }),
+      expectedKey: JSON.stringify(["ref", ["expression", "foo"]]),
+    },
+  ])("should create a ref-based key: $title", ({ column, expectedKey }) => {
+    expect(getLegacyColumnKey(column)).toEqual(expectedKey);
+  });
+
+  it.each<TestCase>([
+    {
+      title: "name-based field ref",
+      column: createMockColumn({
+        name: "foo",
+        field_ref: ["field", "foo", { "base-type": "type/Text" }],
+      }),
+      expectedKey: JSON.stringify(["name", "foo"]),
+    },
+    {
+      title: "aggregation",
+      column: createMockColumn({
+        name: "count",
+        field_ref: ["aggregation", 0],
+      }),
+      expectedKey: JSON.stringify(["name", "count"]),
+    },
+  ])("should create a name-based key: $title", ({ column, expectedKey }) => {
+    expect(getLegacyColumnKey(column)).toEqual(expectedKey);
+  });
+});
+
+describe("getColumnNameFromKey", () => {
+  it("should return the name from a name-based key", () => {
+    expect(getColumnNameFromKey(JSON.stringify(["name", "foo"]))).toBe("foo");
+  });
+
+  it("should ignore a field ref-based key", () => {
+    expect(
+      getColumnNameFromKey(JSON.stringify(["ref", ["field", 1, null]])),
+    ).toBeUndefined();
+  });
+
+  it("should ignore invalid json", () => {
+    expect(getColumnNameFromKey("not a json string")).toBeUndefined();
+  });
+});
+
+describe("getColumnSettings", () => {
+  const column = createMockColumn({
+    name: "foo",
+    field_ref: ["field", 1, { "temporal-unit": "minute" }],
+  });
+
+  it("should ignore missing settings", () => {
+    expect(getColumnSettings(null, column)).toBeUndefined();
+  });
+
+  it("should ignore missing column_settings", () => {
+    const settings = createMockVisualizationSettings({
+      column_settings: undefined,
+    });
+    expect(getColumnSettings(settings, column)).toBeUndefined();
+  });
+
+  it("should prefer legacy keys over new keys", () => {
+    const settings = createMockVisualizationSettings({
+      column_settings: {
+        [getLegacyColumnKey(column)]: { column_title: "A" },
+        [getColumnKey(column)]: { column_title: "B" },
+      },
+    });
+    expect(getColumnSettings(settings, column)).toEqual({
+      column_title: "A",
+    });
+  });
+
+  it("should use new keys if old keys are not available", () => {
+    const settings = createMockVisualizationSettings({
+      column_settings: {
+        [getColumnKey(column)]: { column_title: "B" },
+      },
+    });
+    expect(getColumnSettings(settings, column)).toEqual({
+      column_title: "B",
+    });
+  });
+});
+
+describe("getObjectColumnSettings", () => {
+  const column = createMockColumn({
+    name: "foo",
+    field_ref: ["field", 1, { "temporal-unit": "minute" }],
+  });
+
+  it("should ignore missing settings", () => {
+    expect(getObjectColumnSettings(null, column)).toBeUndefined();
+  });
+
+  it("should prefer legacy keys over new keys", () => {
+    const settings = {
+      [getLegacyColumnKey(column)]: { column_title: "A" },
+      [getColumnKey(column)]: { column_title: "B" },
+    };
+    expect(getObjectColumnSettings(settings, column)).toEqual({
+      column_title: "A",
+    });
+  });
+
+  it("should use new keys if old keys are not available", () => {
+    const settings = {
+      [getColumnKey(column)]: { column_title: "B" },
+    };
+    expect(getObjectColumnSettings(settings, column)).toEqual({
+      column_title: "B",
+    });
+  });
+});
diff --git a/frontend/src/metabase-lib/v1/queries/utils/dataset.ts b/frontend/src/metabase-lib/v1/queries/utils/dataset.ts
index 3608f0a2baa4e9158f91461e49f4234efe2ab671..5a06108edbf42caaa2eda4269fa35060bae56614 100644
--- a/frontend/src/metabase-lib/v1/queries/utils/dataset.ts
+++ b/frontend/src/metabase-lib/v1/queries/utils/dataset.ts
@@ -1,14 +1,12 @@
-import type {
-  DatasetColumn,
-  DatasetData,
-  TableColumnOrderSetting,
-} from "metabase-types/api";
+import type { DatasetData, TableColumnOrderSetting } from "metabase-types/api";
+
+import type { DatasetColumnReference } from "./column-key";
 
 export const datasetContainsNoResults = (data: DatasetData) =>
   data.rows == null || data.rows.length === 0;
 
 export function findColumnIndexesForColumnSettings(
-  columns: Pick<DatasetColumn, "name" | "field_ref">[],
+  columns: DatasetColumnReference[],
   columnSettings: TableColumnOrderSetting[],
 ) {
   const columnIndexByKey = new Map(
@@ -20,7 +18,7 @@ export function findColumnIndexesForColumnSettings(
 }
 
 export function findColumnSettingIndexesForColumns(
-  columns: Pick<DatasetColumn, "name" | "field_ref">[],
+  columns: DatasetColumnReference[],
   columnSettings: TableColumnOrderSetting[],
 ) {
   const columnSettingIndexByKey = new Map(
diff --git a/frontend/src/metabase-lib/v1/queries/utils/get-column-key.ts b/frontend/src/metabase-lib/v1/queries/utils/get-column-key.ts
deleted file mode 100644
index 34c34e53d75059324aa32a9775618eca91cd3eed..0000000000000000000000000000000000000000
--- a/frontend/src/metabase-lib/v1/queries/utils/get-column-key.ts
+++ /dev/null
@@ -1,44 +0,0 @@
-import {
-  createFieldReference,
-  getBaseDimensionReference,
-  getNormalizedDimensionReference,
-  hasStringFieldName,
-  isAggregationReference,
-  isExpressionReference,
-  isFieldReference,
-  isValidDimensionReference,
-} from "metabase-lib/v1/references";
-import type { DatasetColumn } from "metabase-types/api";
-
-export const getColumnKey = (
-  column: Pick<DatasetColumn, "name" | "field_ref">,
-) => {
-  let fieldRef = column.field_ref;
-
-  if (!fieldRef) {
-    fieldRef = createFieldReference(column.name);
-  }
-
-  if (!isValidDimensionReference(fieldRef)) {
-    console.warn("Unknown field_ref", fieldRef);
-    return JSON.stringify(fieldRef);
-  }
-
-  fieldRef = getNormalizedDimensionReference(fieldRef);
-
-  if (
-    isFieldReference(fieldRef) ||
-    isExpressionReference(fieldRef) ||
-    isAggregationReference(fieldRef)
-  ) {
-    fieldRef = getBaseDimensionReference(fieldRef);
-  }
-
-  const isLegacyRef =
-    (isFieldReference(fieldRef) && hasStringFieldName(fieldRef)) ||
-    isAggregationReference(fieldRef);
-
-  return JSON.stringify(
-    isLegacyRef ? ["name", column.name] : ["ref", fieldRef],
-  );
-};
diff --git a/frontend/src/metabase-lib/v1/queries/utils/get-column-key.unit.spec.js b/frontend/src/metabase-lib/v1/queries/utils/get-column-key.unit.spec.js
deleted file mode 100644
index 59495d6ba110c69ce96c8bf98135485d1124d37a..0000000000000000000000000000000000000000
--- a/frontend/src/metabase-lib/v1/queries/utils/get-column-key.unit.spec.js
+++ /dev/null
@@ -1,90 +0,0 @@
-import { getColumnKey } from "metabase-lib/v1/queries/utils/get-column-key";
-
-describe("getColumnKey", () => {
-  // NOTE: run legacy tests with and without a field_ref. without is disabled in latest since it now always uses
-  // field_ref, leaving test code in place to compare against older versions
-  for (const fieldRefEnabled of [/*false,*/ true]) {
-    describe(fieldRefEnabled ? "with field_ref" : "without field_ref", () => {
-      it("should return [ref [field ...]] for field", () => {
-        expect(
-          getColumnKey({
-            name: "foo",
-            id: 1,
-            field_ref: fieldRefEnabled ? ["field", 1, null] : undefined,
-          }),
-        ).toEqual(JSON.stringify(["ref", ["field", 1, null]]));
-      });
-      it("should return [ref [field ...]] for foreign field", () => {
-        expect(
-          getColumnKey({
-            name: "foo",
-            id: 1,
-            fk_field_id: 2,
-            field_ref: fieldRefEnabled
-              ? ["field", 1, { "source-field": 2 }]
-              : undefined,
-          }),
-        ).toEqual(JSON.stringify(["ref", ["field", 1, { "source-field": 2 }]]));
-      });
-      it("should return [ref [expression ...]] for expression", () => {
-        expect(
-          getColumnKey({
-            name: "foo",
-            expression_name: "foo",
-            field_ref: fieldRefEnabled ? ["expression", "foo"] : undefined,
-          }),
-        ).toEqual(JSON.stringify(["ref", ["expression", "foo"]]));
-      });
-      it("should return [name ...] for aggregation", () => {
-        const col = {
-          name: "foo",
-          source: "aggregation",
-          field_ref: fieldRefEnabled ? ["aggregation", 0] : undefined,
-        };
-        expect(getColumnKey(col, [col])).toEqual(
-          // NOTE: not ideal, matches existing behavior, but should be ["aggregation", 0]
-          JSON.stringify(["name", "foo"]),
-        );
-      });
-      it("should return [name ...] for aggregation on field literal", () => {
-        const col = {
-          name: "foo",
-          id: ["field", "foo", { "base-type": "type/Integer" }],
-          field_ref: fieldRefEnabled
-            ? ["field", "foo", { "base-type": "type/Integer" }]
-            : undefined,
-        };
-        expect(getColumnKey(col, [col])).toEqual(
-          // NOTE: not ideal, matches existing behavior, but should be ["field", "foo", {"base-type": "type/Integer"}]
-          JSON.stringify(["name", "foo"]),
-        );
-      });
-      it("should return [field ...] for native query column", () => {
-        expect(
-          getColumnKey({
-            name: "foo",
-            field_ref: fieldRefEnabled
-              ? ["field", "foo", { "base-type": "type/Integer" }]
-              : undefined,
-          }),
-        ).toEqual(
-          // NOTE: not ideal, matches existing behavior, but should be ["field", "foo", {"base-type": "type/Integer"}]
-          JSON.stringify(["name", "foo"]),
-        );
-      });
-    });
-  }
-
-  describe("with field_ref", () => {
-    it("should return [ref [field ...]] for joined field", () => {
-      const col = {
-        name: "foo",
-        id: 1,
-        field_ref: ["field", 1, { "join-alias": "x" }],
-      };
-      expect(getColumnKey(col)).toEqual(
-        JSON.stringify(["ref", ["field", 1, { "join-alias": "x" }]]),
-      );
-    });
-  });
-});
diff --git a/frontend/src/metabase-types/api/card.ts b/frontend/src/metabase-types/api/card.ts
index e954a59e77880a34308321bb5f711079adfbbf3b..3d8c4a6aedfa3368b0fa2190c25b143405393b38 100644
--- a/frontend/src/metabase-types/api/card.ts
+++ b/frontend/src/metabase-types/api/card.ts
@@ -126,6 +126,15 @@ export type XAxisScale = "ordinal" | "histogram" | "timeseries" | NumericScale;
 
 export type YAxisScale = NumericScale;
 
+export interface ColumnSettings {
+  column_title?: string;
+  number_separators?: string;
+  currency?: string;
+
+  // some options are untyped
+  [key: string]: any;
+}
+
 export type VisualizationSettings = {
   "graph.show_values"?: boolean;
   "stackable.stack_type"?: StackType;
@@ -133,6 +142,9 @@ export type VisualizationSettings = {
 
   // Table
   "table.columns"?: TableColumnOrderSetting[];
+  // Keys here can be modern (returned by `getColumnKey`) or legacy (`getLegacyColumnKey`).
+  // Use `getColumnSettings` which checks for both keys.
+  column_settings?: Record<string, ColumnSettings>;
 
   // X-axis
   "graph.x_axis.title_text"?: string;
diff --git a/frontend/src/metabase/admin/datamodel/components/filters/pickers/DefaultPicker/DefaultPicker.tsx b/frontend/src/metabase/admin/datamodel/components/filters/pickers/DefaultPicker/DefaultPicker.tsx
index d2b0d6f41fac2069b3347efa71fc1015855b13f8..1d4fe8ebda6f64c333eb99d9ea95597b260d778d 100644
--- a/frontend/src/metabase/admin/datamodel/components/filters/pickers/DefaultPicker/DefaultPicker.tsx
+++ b/frontend/src/metabase/admin/datamodel/components/filters/pickers/DefaultPicker/DefaultPicker.tsx
@@ -11,7 +11,7 @@ import {
   isFuzzyOperator,
 } from "metabase-lib/v1/operators/utils";
 import type Filter from "metabase-lib/v1/queries/structured/Filter";
-import { getColumnKey } from "metabase-lib/v1/queries/utils/get-column-key";
+import { getColumnSettings } from "metabase-lib/v1/queries/utils/column-key";
 import { isCurrency } from "metabase-lib/v1/types/utils/isa";
 import type { DatasetColumn, FieldId, RowValue } from "metabase-types/api";
 
@@ -64,11 +64,9 @@ export function DefaultPicker({
     ?.question()
     ?.settings();
 
-  const key = dimension?.column?.()
-    ? getColumnKey(dimension.column() as DatasetColumn)
-    : "";
-
-  const columnSettings = visualizationSettings?.column_settings?.[key];
+  const column = dimension?.column?.();
+  const columnSettings =
+    column && getColumnSettings(visualizationSettings, column as DatasetColumn);
 
   const fieldMetadata = field?.metadata?.fields[field?.id as FieldId];
   const fieldSettings = {
diff --git a/frontend/src/metabase/dashboard/components/ClickBehaviorSidebar/ClickBehaviorSidebar.tsx b/frontend/src/metabase/dashboard/components/ClickBehaviorSidebar/ClickBehaviorSidebar.tsx
index f567b938ad58126d83f28da6595544799155427d..301e2ba6b0b87b4ea3edff2e5adc6c727261ee69 100644
--- a/frontend/src/metabase/dashboard/components/ClickBehaviorSidebar/ClickBehaviorSidebar.tsx
+++ b/frontend/src/metabase/dashboard/components/ClickBehaviorSidebar/ClickBehaviorSidebar.tsx
@@ -10,7 +10,7 @@ import {
   canSaveClickBehavior,
   clickBehaviorIsValid,
 } from "metabase-lib/v1/parameters/utils/click-behavior";
-import { getColumnKey } from "metabase-lib/v1/queries/utils/get-column-key";
+import { getColumnKey } from "metabase-lib/v1/queries/utils/column-key";
 import type {
   Dashboard,
   DashCardId,
diff --git a/frontend/src/metabase/dashboard/components/ClickBehaviorSidebar/utils.ts b/frontend/src/metabase/dashboard/components/ClickBehaviorSidebar/utils.ts
index a8c06f652d566a84b89d61474c4d9dc73c0f48ad..57744c0a60ae879d79fd6f4227421d494e6ff0b1 100644
--- a/frontend/src/metabase/dashboard/components/ClickBehaviorSidebar/utils.ts
+++ b/frontend/src/metabase/dashboard/components/ClickBehaviorSidebar/utils.ts
@@ -1,7 +1,5 @@
-import { getIn } from "icepick";
-
 import type { IconName } from "metabase/ui";
-import { getColumnKey } from "metabase-lib/v1/queries/utils/get-column-key";
+import { getColumnSettings } from "metabase-lib/v1/queries/utils/column-key";
 import type {
   ClickBehaviorType,
   DatasetColumn,
@@ -23,10 +21,11 @@ export function getClickBehaviorForColumn(
   dashcard: DashboardCard,
   column: DatasetColumn,
 ) {
-  return getIn(dashcard, [
-    "visualization_settings",
-    "column_settings",
-    getColumnKey(column),
-    "click_behavior",
-  ]);
+  if (dashcard.visualization_settings) {
+    const columnSettings = getColumnSettings(
+      dashcard.visualization_settings,
+      column,
+    );
+    return columnSettings?.click_behavior;
+  }
 }
diff --git a/frontend/src/metabase/querying/utils/viz-settings/sync-viz-settings.ts b/frontend/src/metabase/querying/utils/viz-settings/sync-viz-settings.ts
index 808e7332fc1b55f497528d902d28aba797acec28..311ffc348382c13ce9c6dc9f4b7088d574156258 100644
--- a/frontend/src/metabase/querying/utils/viz-settings/sync-viz-settings.ts
+++ b/frontend/src/metabase/querying/utils/viz-settings/sync-viz-settings.ts
@@ -1,5 +1,10 @@
 import * as Lib from "metabase-lib";
+import {
+  getColumnKey,
+  getColumnNameFromKey,
+} from "metabase-lib/v1/queries/utils/column-key";
 import type {
+  ColumnSettings,
   Series,
   SingleSeries,
   VisualizationSettings,
@@ -53,6 +58,7 @@ export function syncVizSettings(
 ): VisualizationSettings {
   let nextSettings = settings;
   nextSettings = syncTableColumns(nextSettings, newColumns, oldColumns);
+  nextSettings = syncColumnSettings(nextSettings, newColumns, oldColumns);
   nextSettings = syncGraphMetrics(nextSettings, newColumns, oldColumns);
   return nextSettings;
 }
@@ -90,7 +96,7 @@ type SyncColumnNamesOpts<T> = {
   settings: T[];
   newColumns: ColumnInfo[];
   oldColumns: ColumnInfo[];
-  getColumnName: (setting: T) => string;
+  getColumnName: (setting: T) => string | undefined;
   setColumnName: (setting: T, newName: string) => T;
   createSetting: (column: ColumnInfo) => T;
   shouldCreateSetting: (column: ColumnInfo) => boolean | undefined;
@@ -115,8 +121,9 @@ function syncColumns<T>({
     oldColumns.map(column => [column.key, column.name]),
   );
   const remappedSettings = settings.reduce((settings: T[], setting) => {
-    const oldKey = oldKeyByName[getColumnName(setting)];
-    const newName = newNameByKey[oldKey];
+    const oldName = getColumnName(setting);
+    const oldKey = oldName && oldKeyByName[oldName];
+    const newName = oldKey && newNameByKey[oldKey];
     if (!oldKey) {
       settings.push(setting);
     } else if (newName) {
@@ -156,6 +163,32 @@ function syncTableColumns(
   };
 }
 
+function syncColumnSettings(
+  settings: VisualizationSettings,
+  newColumns: ColumnInfo[],
+  oldColumns: ColumnInfo[],
+): VisualizationSettings {
+  const columnSettings = settings["column_settings"];
+  if (!columnSettings) {
+    return settings;
+  }
+
+  const columnEntries = syncColumns<[string, ColumnSettings]>({
+    settings: Object.entries(columnSettings),
+    newColumns,
+    oldColumns,
+    getColumnName: ([key]) => getColumnNameFromKey(key),
+    setColumnName: ([_, setting], name) => [getColumnKey({ name }), setting],
+    createSetting: column => [getColumnKey(column), {}],
+    shouldCreateSetting: () => false,
+  });
+
+  return {
+    ...settings,
+    column_settings: Object.fromEntries(columnEntries),
+  };
+}
+
 function syncGraphMetrics(
   settings: VisualizationSettings,
   newColumns: ColumnInfo[],
diff --git a/frontend/src/metabase/querying/utils/viz-settings/sync-viz-settings.unit.spec.tsx b/frontend/src/metabase/querying/utils/viz-settings/sync-viz-settings.unit.spec.tsx
index b342a8e9ca813ddbeb7f807a4954c6d5aad47338..408a7325112143caf3762ad81c5c6464d73395f8 100644
--- a/frontend/src/metabase/querying/utils/viz-settings/sync-viz-settings.unit.spec.tsx
+++ b/frontend/src/metabase/querying/utils/viz-settings/sync-viz-settings.unit.spec.tsx
@@ -157,6 +157,35 @@ describe("syncVizSettings", () => {
     });
   });
 
+  describe("column_settings", () => {
+    it("should handle adding new columns with column.name changes", () => {
+      const oldColumns: ColumnInfo[] = [
+        { name: "ID", key: "ID" },
+        { name: "ID_2", key: "PEOPLE__ID" },
+      ];
+      const newColumns: ColumnInfo[] = [
+        { name: "ID", key: "ID" },
+        { name: "ID_2", key: "PRODUCTS__ID" },
+        { name: "ID_3", key: "PEOPLE__ID" },
+      ];
+
+      const oldSettings = createMockVisualizationSettings({
+        column_settings: {
+          '["name","ID"]': { column_title: "@ID" },
+          '["name","ID_2"]': { column_title: "ID@" },
+        },
+      });
+
+      const newSettings = syncVizSettings(oldSettings, newColumns, oldColumns);
+      expect(newSettings).toEqual({
+        column_settings: {
+          '["name","ID"]': { column_title: "@ID" },
+          '["name","ID_3"]': { column_title: "ID@" },
+        },
+      });
+    });
+  });
+
   describe("graph.metrics", () => {
     it("should not update the setting if the order of columns has changed", () => {
       const oldColumns: ColumnInfo[] = [
diff --git a/frontend/src/metabase/static-viz/lib/format.ts b/frontend/src/metabase/static-viz/lib/format.ts
index 22d610b2f317f1b490475eb9bbdf1c895ecf3d12..01d7e7d5341e25f98889130a8997344f214d7906 100644
--- a/frontend/src/metabase/static-viz/lib/format.ts
+++ b/frontend/src/metabase/static-viz/lib/format.ts
@@ -19,7 +19,7 @@ import type {
 } from "metabase/visualizations/shared/types/format";
 import { getLabelsMetricColumn } from "metabase/visualizations/shared/utils/series";
 import type { RemappingHydratedDatasetColumn } from "metabase/visualizations/types";
-import { getColumnKey } from "metabase-lib/v1/queries/utils/get-column-key";
+import { getColumnSettings } from "metabase-lib/v1/queries/utils/column-key";
 import { rangeForValue } from "metabase-lib/v1/queries/utils/range-for-value";
 import {
   isCoordinate,
@@ -109,7 +109,7 @@ export const getStaticFormatters = (
 ): ChartTicksFormatters => {
   const yTickFormatter = (value: StringLike) => {
     const column = chartColumns.dimension.column;
-    const columnSettings = settings.column_settings?.[getColumnKey(column)];
+    const columnSettings = getColumnSettings(settings, column);
     const valueToFormat = getRemappedValue(value, column);
 
     const options = getFormattingOptionsWithoutScaling({
@@ -125,8 +125,10 @@ export const getStaticFormatters = (
 
   const percentXTicksFormatter = (percent: NumberLike) => {
     const column = metricColumn.column;
-    const number_separators =
-      settings.column_settings?.[getColumnKey(column)]?.number_separators;
+    const number_separators = getColumnSettings(
+      settings,
+      column,
+    )?.number_separators;
 
     const options = getFormattingOptionsWithoutScaling({
       column,
@@ -141,7 +143,7 @@ export const getStaticFormatters = (
 
   const xTickFormatter = (value: NumberLike) => {
     const column = metricColumn.column;
-    const columnSettings = settings.column_settings?.[getColumnKey(column)];
+    const columnSettings = getColumnSettings(settings, column);
     const valueToFormat = getRemappedValue(value, column);
 
     const options = getFormattingOptionsWithoutScaling({
@@ -168,7 +170,7 @@ export const getLabelsStaticFormatter = (
   settings: VisualizationSettings,
 ): ValueFormatter => {
   const column = getLabelsMetricColumn(chartColumns).column;
-  const columnSettings = settings.column_settings?.[getColumnKey(column)];
+  const columnSettings = getColumnSettings(settings, column);
   const options = getFormattingOptionsWithoutScaling({
     column,
     ...columnSettings,
diff --git a/frontend/src/metabase/static-viz/lib/settings.ts b/frontend/src/metabase/static-viz/lib/settings.ts
index 2641b98f007d8eb6afcf40248096d4bbb7220a6b..b5e0fd0c1884e3918ae5b90182b6af0da42ffbc2 100644
--- a/frontend/src/metabase/static-viz/lib/settings.ts
+++ b/frontend/src/metabase/static-viz/lib/settings.ts
@@ -9,8 +9,7 @@ import type {
   ComputedVisualizationSettings,
   RemappingHydratedDatasetColumn,
 } from "metabase/visualizations/types";
-import { getColumnKey } from "metabase-lib/v1/queries/utils/get-column-key";
-import { normalize } from "metabase-lib/v1/queries/utils/normalize";
+import { getObjectColumnSettings } from "metabase-lib/v1/queries/utils/column-key";
 import { isCoordinate, isNumber } from "metabase-lib/v1/types/utils/isa";
 import type {
   DatasetColumn,
@@ -33,14 +32,11 @@ const getColumnSettings = (
   column: DatasetColumn,
   settings: VisualizationSettings,
 ): Record<string, unknown> => {
-  const columnKey = Object.keys(settings.column_settings ?? {}).find(
-    possiblyDenormalizedFieldRef =>
-      normalize(possiblyDenormalizedFieldRef) === getColumnKey(column),
+  const storedSettings = getObjectColumnSettings(
+    settings.column_settings,
+    column,
   );
-
-  const columnSettings = columnKey
-    ? { column, ...column.settings, ...settings.column_settings?.[columnKey] }
-    : { column, ...column.settings };
+  const columnSettings = { column, ...column.settings, ...storedSettings };
 
   if (isNumber(column) && !isCoordinate(column)) {
     fillWithDefaultValue(columnSettings, "currency", getDefaultCurrency());
diff --git a/frontend/src/metabase/visualizations/click-actions/actions/ColumnFormattingAction/ColumnFormattingAction.tsx b/frontend/src/metabase/visualizations/click-actions/actions/ColumnFormattingAction/ColumnFormattingAction.tsx
index 7dd0fa04b3b1a933a43dec946dc4a1a2bb717b8f..2c68422d352386276412d9c9f16bd7cecc9ded60 100644
--- a/frontend/src/metabase/visualizations/click-actions/actions/ColumnFormattingAction/ColumnFormattingAction.tsx
+++ b/frontend/src/metabase/visualizations/click-actions/actions/ColumnFormattingAction/ColumnFormattingAction.tsx
@@ -8,7 +8,7 @@ import type {
   LegacyDrill,
 } from "metabase/visualizations/types";
 import * as Lib from "metabase-lib";
-import { getColumnKey } from "metabase-lib/v1/queries/utils/get-column-key";
+import { getColumnKey } from "metabase-lib/v1/queries/utils/column-key";
 import type { VisualizationSettings } from "metabase-types/api";
 
 import { PopoverRoot } from "./ColumnFormattingAction.styled";
diff --git a/frontend/src/metabase/visualizations/components/ChartSettings.jsx b/frontend/src/metabase/visualizations/components/ChartSettings.jsx
index c3585ffacc8f30d6baaab6934319c474c19b3704..ce175caed7c05c24b801544ae5f168e37a82ea27 100644
--- a/frontend/src/metabase/visualizations/components/ChartSettings.jsx
+++ b/frontend/src/metabase/visualizations/components/ChartSettings.jsx
@@ -24,7 +24,7 @@ import {
 import { getSettingDefinitionsForColumn } from "metabase/visualizations/lib/settings/column";
 import { keyForSingleSeries } from "metabase/visualizations/lib/settings/series";
 import { getSettingsWidgetsForSeries } from "metabase/visualizations/lib/settings/visualization";
-import { getColumnKey } from "metabase-lib/v1/queries/utils/get-column-key";
+import { getColumnKey } from "metabase-lib/v1/queries/utils/column-key";
 
 import {
   SectionContainer,
diff --git a/frontend/src/metabase/visualizations/components/settings/ChartSettingFieldPicker.jsx b/frontend/src/metabase/visualizations/components/settings/ChartSettingFieldPicker.jsx
index 750fae32efc6ba0f39742c00b19402061cac1203..4639ed19e559b1938142482405a0d71fd82131a1 100644
--- a/frontend/src/metabase/visualizations/components/settings/ChartSettingFieldPicker.jsx
+++ b/frontend/src/metabase/visualizations/components/settings/ChartSettingFieldPicker.jsx
@@ -3,7 +3,7 @@ import { t } from "ttag";
 import _ from "underscore";
 
 import { keyForSingleSeries } from "metabase/visualizations/lib/settings/series";
-import { getColumnKey } from "metabase-lib/v1/queries/utils/get-column-key";
+import { getColumnKey } from "metabase-lib/v1/queries/utils/column-key";
 
 import {
   SettingsIcon,
diff --git a/frontend/src/metabase/visualizations/components/settings/ChartSettingFieldsPartition.jsx b/frontend/src/metabase/visualizations/components/settings/ChartSettingFieldsPartition.jsx
index b5fb765347b12cfc47096b58fa0c40153a568fe8..d8f13c66ad9ed70dae21ee899d8feaecd1e20173 100644
--- a/frontend/src/metabase/visualizations/components/settings/ChartSettingFieldsPartition.jsx
+++ b/frontend/src/metabase/visualizations/components/settings/ChartSettingFieldsPartition.jsx
@@ -9,7 +9,7 @@ import _ from "underscore";
 import Label from "metabase/components/type/Label";
 import { DragDropContext } from "metabase/core/components/DragDropContext";
 import CS from "metabase/css/core/index.css";
-import { getColumnKey } from "metabase-lib/v1/queries/utils/get-column-key";
+import { getColumnKey } from "metabase-lib/v1/queries/utils/column-key";
 
 import {
   DroppableContainer,
diff --git a/frontend/src/metabase/visualizations/components/settings/ChartSettingNestedSettings.jsx b/frontend/src/metabase/visualizations/components/settings/ChartSettingNestedSettings.jsx
index 9153279194efa367623ccd7e21152181422bb79d..00e9af0a7753f9aa920b35f6fd46daecae853645 100644
--- a/frontend/src/metabase/visualizations/components/settings/ChartSettingNestedSettings.jsx
+++ b/frontend/src/metabase/visualizations/components/settings/ChartSettingNestedSettings.jsx
@@ -11,7 +11,7 @@ import ChartSettingsWidget from "../ChartSettingsWidget";
  * @deprecated HOCs are deprecated
  */
 const chartSettingNestedSettings =
-  ({ getObjectKey, getSettingsWidgetsForObject }) =>
+  ({ getObjectKey, getObjectSettings, getSettingsWidgetsForObject }) =>
   ComposedComponent =>
     class extends Component {
       constructor(props) {
@@ -55,15 +55,23 @@ const chartSettingNestedSettings =
         }
       };
 
-      handleChangeSettingsForObjectKey = (objectKey, changedSettings) => {
-        const { onChange } = this.props;
-        const objectsSettings = this.props.value || {};
-        const objectSettings = objectsSettings[objectKey] || {};
-        const newSettings = updateSettings(objectSettings, changedSettings);
-        onChange({
-          ...objectsSettings,
-          [objectKey]: newSettings,
-        });
+      handleChangeSettingsForObjectKey = (changedKey, changedSettings) => {
+        const { objects, onChange } = this.props;
+        const oldSettings = this.props.value || {};
+        const newSettings = objects.reduce((newSettings, object) => {
+          const currentKey = getObjectKey(object);
+          const objectSettings = getObjectSettings(oldSettings, object);
+          if (currentKey === changedKey) {
+            newSettings[currentKey] = updateSettings(
+              objectSettings,
+              changedSettings,
+            );
+          } else {
+            newSettings[currentKey] = objectSettings;
+          }
+          return newSettings;
+        }, {});
+        onChange(newSettings);
       };
 
       render() {
@@ -76,7 +84,8 @@ const chartSettingNestedSettings =
           );
           if (editingObject) {
             const objectsSettings = this.props.value || {};
-            const objectSettings = objectsSettings[editingObjectKey] || {};
+            const objectSettings =
+              getObjectSettings(objectsSettings, editingObject) ?? {};
             const objectSettingsWidgets = getSettingsWidgetsForObject(
               series,
               editingObject,
diff --git a/frontend/src/metabase/visualizations/components/settings/ChartSettingTableColumns/TableColumnPanel/utils.ts b/frontend/src/metabase/visualizations/components/settings/ChartSettingTableColumns/TableColumnPanel/utils.ts
index 1b49edb770b2baaf03d88a8e685f8655c815967d..0cb8d64620ac261b6d3ba28aab193a9702720e8f 100644
--- a/frontend/src/metabase/visualizations/components/settings/ChartSettingTableColumns/TableColumnPanel/utils.ts
+++ b/frontend/src/metabase/visualizations/components/settings/ChartSettingTableColumns/TableColumnPanel/utils.ts
@@ -1,7 +1,7 @@
 import type { IconName } from "metabase/ui";
 import { getIconForField } from "metabase-lib/v1/metadata/utils/fields";
+import { getColumnKey } from "metabase-lib/v1/queries/utils/column-key";
 import { findColumnIndexesForColumnSettings } from "metabase-lib/v1/queries/utils/dataset";
-import { getColumnKey } from "metabase-lib/v1/queries/utils/get-column-key";
 import type {
   DatasetColumn,
   TableColumnOrderSetting,
diff --git a/frontend/src/metabase/visualizations/components/settings/ChartSettingsListColumns/ChartSettingsListColumns.tsx b/frontend/src/metabase/visualizations/components/settings/ChartSettingsListColumns/ChartSettingsListColumns.tsx
index 15fc8bba6040e24323b036bdee8dbdb9cd8cf20d..ab564b66b97aaac37a6a14a1c09c841256e18a53 100644
--- a/frontend/src/metabase/visualizations/components/settings/ChartSettingsListColumns/ChartSettingsListColumns.tsx
+++ b/frontend/src/metabase/visualizations/components/settings/ChartSettingsListColumns/ChartSettingsListColumns.tsx
@@ -5,7 +5,7 @@ import _ from "underscore";
 
 import Button from "metabase/core/components/Button";
 import type Question from "metabase-lib/v1/Question";
-import { getColumnKey } from "metabase-lib/v1/queries/utils/get-column-key";
+import { getColumnKey } from "metabase-lib/v1/queries/utils/column-key";
 import type {
   ConcreteFieldReference,
   DatasetColumn,
diff --git a/frontend/src/metabase/visualizations/echarts/cartesian/model/util.ts b/frontend/src/metabase/visualizations/echarts/cartesian/model/util.ts
index 203451274e23e5a7391b9232c1cd0626b477dec9..217d9a2f23cbf68d3adeaa8a588e39efc91f2d48 100644
--- a/frontend/src/metabase/visualizations/echarts/cartesian/model/util.ts
+++ b/frontend/src/metabase/visualizations/echarts/cartesian/model/util.ts
@@ -3,7 +3,7 @@ import type {
   ComputedVisualizationSettings,
   RemappingHydratedDatasetColumn,
 } from "metabase/visualizations/types";
-import { getColumnKey } from "metabase-lib/v1/queries/utils/get-column-key";
+import { getColumnSettings } from "metabase-lib/v1/queries/utils/column-key";
 
 import {
   NEGATIVE_BAR_DATA_LABEL_KEY_SUFFIX,
@@ -28,8 +28,7 @@ export function getColumnScaling(
   settings: ComputedVisualizationSettings,
 ) {
   const columnSettings =
-    settings.column?.(column) ??
-    settings.column_settings?.[getColumnKey(column)];
+    settings.column?.(column) ?? getColumnSettings(settings, column);
   const scale = columnSettings?.scale;
   return Number.isFinite(scale) ? (scale as number) : 1;
 }
diff --git a/frontend/src/metabase/visualizations/lib/settings/column.js b/frontend/src/metabase/visualizations/lib/settings/column.js
index 77319f7859f2dc15e0ac83b79079470d3f7c8872..1e8b79d73358317bd9f9a61cba2398cf332d55d4 100644
--- a/frontend/src/metabase/visualizations/lib/settings/column.js
+++ b/frontend/src/metabase/visualizations/lib/settings/column.js
@@ -23,7 +23,10 @@ import {
   isDateWithoutTime,
   isNumber,
 } from "metabase-lib/v1/types/utils/isa";
-import { getColumnKey } from "metabase-lib/v1/queries/utils/get-column-key";
+import {
+  getColumnKey,
+  getObjectColumnSettings,
+} from "metabase-lib/v1/queries/utils/column-key";
 import {
   findColumnIndexesForColumnSettings,
   findColumnSettingIndexesForColumns,
@@ -67,6 +70,7 @@ export function columnSettings({
     objectName: "column",
     getObjects: getColumns,
     getObjectKey: getColumnKey,
+    getObjectSettings: getObjectColumnSettings,
     getSettingDefinitionsForObject: getSettingDefinitionsForColumn,
     component: ChartNestedSettingColumns,
     getInheritedSettingsForObject: getInhertiedSettingsForColumn,
diff --git a/frontend/src/metabase/visualizations/lib/settings/nested.js b/frontend/src/metabase/visualizations/lib/settings/nested.js
index c49187f3b125db02cf34c8123d2d20653af781c1..3bb60312e2f14c794ba6f21ac346c357e97dd7ef 100644
--- a/frontend/src/metabase/visualizations/lib/settings/nested.js
+++ b/frontend/src/metabase/visualizations/lib/settings/nested.js
@@ -11,6 +11,7 @@ export function nestedSettings(
     objectName = "object",
     getObjects,
     getObjectKey,
+    getObjectSettings,
     getSettingDefinitionsForObject,
     getInheritedSettingsForObject = () => ({}),
     component,
@@ -42,7 +43,7 @@ export function nestedSettings(
       allComputedSettings[key] = getComputedSettingsForObject(
         series,
         object,
-        allStoredSettings[key] || {},
+        getObjectSettings(allStoredSettings, object) ?? {},
         extra,
       );
     }
@@ -77,6 +78,7 @@ export function nestedSettings(
   // decorate with nested settings HOC
   const widget = chartSettingNestedSettings({
     getObjectKey,
+    getObjectSettings,
     getSettingsWidgetsForObject,
   })(component);
 
@@ -112,7 +114,8 @@ export function nestedSettings(
           const key = getObjectKey(object);
           if (!cache.has(key)) {
             const inheritedSettings = getInheritedSettingsForObject(object);
-            const storedSettings = settings[id][key] || {};
+            const storedSettings =
+              getObjectSettings(settings[id], object) ?? {};
             cache.set(key, {
               ...getComputedSettingsForObject(
                 series,
diff --git a/frontend/src/metabase/visualizations/lib/settings/nested.unit.spec.js b/frontend/src/metabase/visualizations/lib/settings/nested.unit.spec.js
index 00e54303a457da9feb99ae7de35f2b92a6435a83..3b036b6a2674a3cbd4eabbb818ab9e67e4e34520 100644
--- a/frontend/src/metabase/visualizations/lib/settings/nested.unit.spec.js
+++ b/frontend/src/metabase/visualizations/lib/settings/nested.unit.spec.js
@@ -8,6 +8,7 @@ describe("nestedSettings", () => {
         objectName: "nested",
         getObjects: () => [1, 2, 3],
         getObjectKey: object => String(object),
+        getObjectSettings: (objects, key) => objects[key],
         getSettingDefinitionsForObject: () => ({
           foo: { getDefault: object => `foo${object}` },
         }),
diff --git a/frontend/src/metabase/visualizations/lib/settings/series.js b/frontend/src/metabase/visualizations/lib/settings/series.js
index c28f0da8c48287d27169efa7cabb398e86ff0131..c65a68de7d031d52a4c4b9668385345183a09aa7 100644
--- a/frontend/src/metabase/visualizations/lib/settings/series.js
+++ b/frontend/src/metabase/visualizations/lib/settings/series.js
@@ -1,6 +1,5 @@
 import { getIn } from "icepick";
 import { t } from "ttag";
-import _ from "underscore";
 
 import ChartNestedSettingSeries from "metabase/visualizations/components/settings/ChartNestedSettingSeries";
 import {
@@ -205,6 +204,8 @@ export function seriesSetting({
       objectName: "series",
       getObjects: (series, settings) => series,
       getObjectKey: keyForSingleSeries,
+      getObjectSettings: (settings, object) =>
+        settings[keyForSingleSeries(object)],
       getSettingDefinitionsForObject: getSettingDefinitionsForSingleSeries,
       component: ChartNestedSettingSeries,
       readDependencies: [SERIES_COLORS_SETTING_KEY, ...readDependencies],
diff --git a/frontend/src/metabase/visualizations/lib/utils.js b/frontend/src/metabase/visualizations/lib/utils.js
index 353c37253942e01c9d7bb45a2bbcd6436fe6a8a3..ecb56d212eec60f342d32242a220450e7d2eadf3 100644
--- a/frontend/src/metabase/visualizations/lib/utils.js
+++ b/frontend/src/metabase/visualizations/lib/utils.js
@@ -4,7 +4,7 @@ import { t } from "ttag";
 import _ from "underscore";
 
 import { isNotNull } from "metabase/lib/types";
-import { getColumnKey } from "metabase-lib/v1/queries/utils/get-column-key";
+import { getColumnKey } from "metabase-lib/v1/queries/utils/column-key";
 import { isDimension, isMetric, isDate } from "metabase-lib/v1/types/utils/isa";
 
 export const MAX_SERIES = 100;
diff --git a/frontend/src/metabase/visualizations/shared/settings/column.ts b/frontend/src/metabase/visualizations/shared/settings/column.ts
index 69430bff25511dbf79de5cc1c3aef894e669f59e..a9a72be0c8e23fffb34615fe45c1b31c54f26a77 100644
--- a/frontend/src/metabase/visualizations/shared/settings/column.ts
+++ b/frontend/src/metabase/visualizations/shared/settings/column.ts
@@ -1,9 +1,9 @@
 import { isCurrency, isPercentage } from "metabase-lib/v1/types/utils/isa";
-import type { DatasetColumn } from "metabase-types/api";
+import type { ColumnSettings, DatasetColumn } from "metabase-types/api";
 
 export function getDefaultNumberStyle(
   column: DatasetColumn,
-  columnSettings: Record<string, string>,
+  columnSettings: ColumnSettings,
 ) {
   if (isCurrency(column) && columnSettings["currency"]) {
     return "currency";
@@ -46,7 +46,7 @@ const CURRENCIES_WITH_SYMBOLS = new Set([
 
 export function getDefaultCurrencyStyle(
   _column: any,
-  columnSettings: Record<string, string>,
+  columnSettings: ColumnSettings,
 ) {
   const c = columnSettings["currency"] || "USD";
   return CURRENCIES_WITH_SYMBOLS.has(c) ? "symbol" : "code";
diff --git a/frontend/src/metabase/visualizations/visualizations/Table.unit.spec.js b/frontend/src/metabase/visualizations/visualizations/Table.unit.spec.js
index 99259d248d527ac72d1a680b564956b4191c9fa0..72d9da2f296b1242c33a30efe5394379974e26e6 100644
--- a/frontend/src/metabase/visualizations/visualizations/Table.unit.spec.js
+++ b/frontend/src/metabase/visualizations/visualizations/Table.unit.spec.js
@@ -7,8 +7,10 @@ import { renderWithProviders, screen, within } from "__support__/ui";
 import ChartSettings from "metabase/visualizations/components/ChartSettings";
 import registerVisualizations from "metabase/visualizations/register";
 import Question from "metabase-lib/v1/Question";
+import { createMockVisualizationSettings } from "metabase-types/api/mocks";
 import {
   createSampleDatabase,
+  ORDERS,
   ORDERS_ID,
   SAMPLE_DB_ID,
 } from "metabase-types/api/mocks/presets";
@@ -20,7 +22,9 @@ const metadata = createMockMetadata({
 });
 const ordersTable = metadata.table(ORDERS_ID);
 
-const setup = ({ vizType }) => {
+const setup = ({ display, visualization_settings = {} }) => {
+  const onChange = jest.fn();
+
   const Container = () => {
     const [question, setQuestion] = useState(
       new Question(
@@ -32,14 +36,15 @@ const setup = ({ vizType }) => {
             },
             database: SAMPLE_DB_ID,
           },
-          display: vizType,
-          visualization_settings: {},
+          display,
+          visualization_settings,
         },
         metadata,
       ),
     );
 
-    const onChange = update => {
+    const handleChange = update => {
+      onChange(update);
       setQuestion(q => {
         const newQuestion = q.updateSettings(update);
         return new Question(thaw(newQuestion.card()), metadata);
@@ -48,7 +53,7 @@ const setup = ({ vizType }) => {
 
     return (
       <ChartSettings
-        onChange={onChange}
+        onChange={handleChange}
         series={[
           {
             card: question.card(),
@@ -66,13 +71,15 @@ const setup = ({ vizType }) => {
   };
 
   renderWithProviders(<Container />);
+
+  return { onChange };
 };
 
 // these visualizations share column settings, so all the tests should work for both
-["table", "object"].forEach(vizType => {
-  describe(`${vizType} column settings`, () => {
+["table", "object"].forEach(display => {
+  describe(`${display} column settings`, () => {
     it("should show you related columns in structured queries", async () => {
-      setup({ vizType });
+      setup({ display });
       await userEvent.click(screen.getByText("Add or remove columns"));
 
       expect(screen.getByText("User")).toBeInTheDocument();
@@ -85,7 +92,7 @@ const setup = ({ vizType }) => {
     });
 
     it("should allow you to show and hide columns", async () => {
-      setup({ vizType });
+      setup({ display });
       await userEvent.click(await screen.findByTestId("Tax-hide-button"));
 
       expect(
@@ -98,7 +105,7 @@ const setup = ({ vizType }) => {
     });
 
     it("should allow you to update a column name", async () => {
-      setup({ vizType });
+      setup({ display });
       await userEvent.click(
         await screen.findByTestId("Subtotal-settings-button"),
       );
@@ -109,5 +116,34 @@ const setup = ({ vizType }) => {
       await userEvent.click(await screen.findByText("Tax"));
       expect(await screen.findByText("Subtotal Updated")).toBeInTheDocument();
     });
+
+    it("should rewrite field ref-based column_settings keys to name-based keys on update", async () => {
+      const { onChange } = setup({
+        display,
+        visualization_settings: createMockVisualizationSettings({
+          column_settings: {
+            [JSON.stringify(["ref", ["field", ORDERS.TOTAL, null]])]: {
+              column_title: "Total1",
+            },
+            [JSON.stringify(["ref", ["field", ORDERS.SUBTOTAL, null]])]: {
+              column_title: "Subtotal1",
+            },
+          },
+        }),
+      });
+      await userEvent.click(
+        await screen.findByTestId("Subtotal1-settings-button"),
+      );
+      const input = await screen.findByDisplayValue("Subtotal1");
+      await userEvent.clear(input);
+      await userEvent.type(input, "Subtotal2");
+      await userEvent.click(await screen.findByText("Total1"));
+      expect(onChange).toHaveBeenCalledWith({
+        column_settings: {
+          [JSON.stringify(["name", "TOTAL"])]: { column_title: "Total1" },
+          [JSON.stringify(["name", "SUBTOTAL"])]: { column_title: "Subtotal2" },
+        },
+      });
+    });
   });
 });
diff --git a/src/metabase/formatter/datetime.clj b/src/metabase/formatter/datetime.clj
index 63b8d1411c17a35b5a99cd43b2c2c75984f7fd83..3b5128a9e5bc203402045928c52fbc02991e5b63 100644
--- a/src/metabase/formatter/datetime.clj
+++ b/src/metabase/formatter/datetime.clj
@@ -62,7 +62,8 @@
                               ;; match a key with metadata, even if we do have the correct name or id
                               (update-keys #(select-keys % [::mb.viz/field-id ::mb.viz/column-name])))]
     (or (all-cols-settings {::mb.viz/field-id field-id-or-name})
-        (all-cols-settings {::mb.viz/column-name (or field-id-or-name column-name)}))))
+        (all-cols-settings {::mb.viz/column-name field-id-or-name})
+        (all-cols-settings {::mb.viz/column-name column-name}))))
 
 (defn- determine-time-format
   "Given viz-settings with a time-style and possible time-enabled (precision) entry, create the format string.
diff --git a/src/metabase/query_processor/streaming/common.clj b/src/metabase/query_processor/streaming/common.clj
index 1056c4110b74efc819a6536e7b2a055e9972d496..f3fa7d8c3b13b33d02ad9921747613c6592e0483 100644
--- a/src/metabase/query_processor/streaming/common.clj
+++ b/src/metabase/query_processor/streaming/common.clj
@@ -101,7 +101,8 @@
                               (:name col))
           col-settings'   (update-keys col-settings #(select-keys % [::mb.viz/field-id ::mb.viz/column-name]))
           format-settings (or (get col-settings' {::mb.viz/field-id id-or-name})
-                              (get col-settings' {::mb.viz/column-name id-or-name}))
+                              (get col-settings' {::mb.viz/column-name id-or-name})
+                              (get col-settings' {::mb.viz/column-name (:name col)}))
           is-currency?    (or (isa? (:semantic_type col) :type/Currency)
                               (= (::mb.viz/number-style format-settings) "currency"))
           merged-settings (if is-currency?
diff --git a/src/metabase/query_processor/streaming/xlsx.clj b/src/metabase/query_processor/streaming/xlsx.clj
index 3aecd54fc82766baa30e21582ba2060129b07665..60d4595b12a799d546ec9d97b11c97e3cee7ac09 100644
--- a/src/metabase/query_processor/streaming/xlsx.clj
+++ b/src/metabase/query_processor/streaming/xlsx.clj
@@ -449,7 +449,8 @@
               styles (.next sty-it)
               id-or-name   (or (:id col) (:name col))
               settings     (or (get col-settings {::mb.viz/field-id id-or-name})
-                               (get col-settings {::mb.viz/column-name id-or-name}))
+                               (get col-settings {::mb.viz/column-name id-or-name})
+                               (get col-settings {::mb.viz/column-name (:name col)}))
               scaled-val   (if (and value (::mb.viz/scale settings))
                              (* value (::mb.viz/scale settings))
                              value)
@@ -480,7 +481,8 @@
               styles (.next sty-it)
               id-or-name   (or (:id col) (:name col))
               settings     (or (get col-settings {::mb.viz/field-id id-or-name})
-                               (get col-settings {::mb.viz/column-name id-or-name}))
+                               (get col-settings {::mb.viz/column-name id-or-name})
+                               (get col-settings {::mb.viz/column-name (:name col)}))
               scaled-val   (if (and value (::mb.viz/scale settings))
                              (* value (::mb.viz/scale settings))
                              value)