diff --git a/e2e/test/scenarios/models/models-metadata.cy.spec.js b/e2e/test/scenarios/models/models-metadata.cy.spec.js
index 12779aef0e38d6615eaffe6101c6f17f93ebd434..53d94eb2465647330d44b360c7160a3c80dea955 100644
--- a/e2e/test/scenarios/models/models-metadata.cy.spec.js
+++ b/e2e/test/scenarios/models/models-metadata.cy.spec.js
@@ -152,6 +152,28 @@ describe("scenarios > models metadata", () => {
     cy.findByText("Pre-tax ($)");
   });
 
+  it("should allow setting column relations (metabase#29318)", () => {
+    cy.createNativeQuestion(
+      {
+        name: "Native Model",
+        dataset: true,
+        native: {
+          query: "SELECT * FROM ORDERS",
+        },
+      },
+      { visitQuestion: true },
+    );
+    openQuestionActions();
+    cy.findByText("Edit metadata").click();
+    openColumnOptions("USER_ID");
+    setColumnType("No special type", "Foreign Key");
+    cy.findByText("Select a target").click();
+    cy.findByText("People → ID").click();
+    cy.button("Save changes").click();
+    // TODO: Not much to do with it at the moment beyond saving it.
+    // Check that the relation is automatically suggested in the notebook once it is implemented.
+  });
+
   it("should keep metadata in sync with the query", () => {
     cy.createNativeQuestion(
       {
diff --git a/frontend/src/metabase-types/guards/forms.ts b/frontend/src/metabase-types/guards/forms.ts
index e1ea0900b0cc037bfade5b6aead9e2014943c650..996932219408171812feacd27cce267e2d71304f 100644
--- a/frontend/src/metabase-types/guards/forms.ts
+++ b/frontend/src/metabase-types/guards/forms.ts
@@ -3,12 +3,13 @@ import type {
   CustomFormFieldDefinition,
   FormFieldDefinition,
 } from "metabase-types/forms";
+import { isReactComponent } from "./react";
 
 export function isCustomWidget(
   formField: FormFieldDefinition,
 ): formField is CustomFormFieldDefinition {
   return (
     !(formField as StandardFormFieldDefinition).type &&
-    typeof (formField as CustomFormFieldDefinition).widget === "function"
+    isReactComponent((formField as CustomFormFieldDefinition).widget)
   );
 }
diff --git a/frontend/src/metabase-types/guards/react.ts b/frontend/src/metabase-types/guards/react.ts
index 0fa5ae58f48e2d70bd14a89d94df839a71d135d7..d31d9170155e169dc9fef39da170084d86743318 100644
--- a/frontend/src/metabase-types/guards/react.ts
+++ b/frontend/src/metabase-types/guards/react.ts
@@ -8,3 +8,15 @@ export function isReactDOMTypeElement(
 ): element is React.ReactElement {
   return ReactIs.isElement(element) && typeof element.type === "string";
 }
+
+export function isReactComponent(
+  component: any,
+): component is React.FC | React.Component | React.ExoticComponent {
+  return (
+    typeof component === "function" ||
+    // Checking for "Exotic" components such as ones returned by memo, forwardRef
+    (typeof component === "object" &&
+      "$$typeof" in component &&
+      typeof component["$$typeof"] === "symbol")
+  );
+}