diff --git a/web/package.json b/web/package.json
index 046126c66..d7bb3d505 100644
--- a/web/package.json
+++ b/web/package.json
@@ -83,7 +83,7 @@
     "@material-ui/icons": "^4.11.2",
     "@material-ui/lab": "4.0.0-alpha.58",
     "@material-ui/pickers": "^3.2.10",
-    "@projectstorm/react-diagrams": "^6.4.2",
+    "@projectstorm/react-diagrams": "^6.6.1",
     "@simonwep/pickr": "^1.5.1",
     "@tippyjs/react": "^4.2.0",
     "@types/classnames": "^2.2.6",
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/columns/static/js/column.ui.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/columns/static/js/column.ui.js
index ee6edcd1b..f57d540f0 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/columns/static/js/column.ui.js
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/columns/static/js/column.ui.js
@@ -19,7 +19,7 @@ export function getNodeColumnSchema(treeNodeInfo, itemNodeData, pgBrowser) {
 }
 
 export default class ColumnSchema extends BaseUISchema {
-  constructor(getPrivilegeRoleSchema, nodeInfo, cltypeOptions, collspcnameOptions) {
+  constructor(getPrivilegeRoleSchema, nodeInfo, cltypeOptions, collspcnameOptions, inErd=false) {
     super({
       name: undefined,
       attowner: undefined,
@@ -57,6 +57,7 @@ export default class ColumnSchema extends BaseUISchema {
     this.nodeInfo = nodeInfo;
     this.cltypeOptions = cltypeOptions;
     this.collspcnameOptions = collspcnameOptions;
+    this.inErd = inErd;
 
     this.datatypes = [];
   }
@@ -71,8 +72,7 @@ export default class ColumnSchema extends BaseUISchema {
       return true;
     }
 
-    if('schema' in this.nodeInfo)
-    {
+    if(this.nodeInfo &&  ('schema' in this.nodeInfo)) {
       // We will disable control if it's system columns
       // inheritedfrom check is useful when we use this schema in table node
       // inheritedfrom has value then we should disable it
@@ -86,7 +86,7 @@ export default class ColumnSchema extends BaseUISchema {
       // ie: it's position is less than 1
       return !(!_.isUndefined(state.attnum) && state.attnum > 0);
     }
-    return true;
+    return false;
   }
 
   editableCheckForTable(state) {
@@ -179,7 +179,7 @@ export default class ColumnSchema extends BaseUISchema {
           ) || (
             'is_partitioned' in obj.top.origData
             && obj.top.origData['is_partitioned']
-            && obj.nodeInfo.server && obj.nodeInfo.server.version < 11000
+            && obj.getServerVersion() < 11000
           ))
         ) {
           return true;
@@ -239,7 +239,7 @@ export default class ColumnSchema extends BaseUISchema {
             filter: (options)=>{
               let result = options;
               let edit_types = state?.edit_types || [];
-              if(!obj.isNew(state)) {
+              if(!obj.isNew(state) && !this.inErd) {
                 result = _.filter(options, (o)=>edit_types.indexOf(o.value) > -1);
               }
               return result;
@@ -256,7 +256,7 @@ export default class ColumnSchema extends BaseUISchema {
             filter: (options)=>{
               let result = options;
               let edit_types = row?.edit_types || [];
-              if(!obj.isNew(row)) {
+              if(!obj.isNew(row) && !this.inErd) {
                 result = _.filter(options, (o)=>edit_types.indexOf(o.value) > -1);
               }
               return result;
@@ -272,7 +272,10 @@ export default class ColumnSchema extends BaseUISchema {
       id: 'inheritedfrom', label: gettext('Inherited from table'),
       type: 'text', readonly: true, editable: false,
       visible: function() {
-        return _.isUndefined(this.nodeInfo['table'] || this.nodeInfo['view'] || this.nodeInfo['mview']);
+        if(this.nodeInfo) {
+          return _.isUndefined(this.nodeInfo['table'] || this.nodeInfo['view'] || this.nodeInfo['mview']);
+        }
+        return false;
       },
     },{
       id: 'attlen', label: gettext('Length/Precision'),
@@ -417,8 +420,7 @@ export default class ColumnSchema extends BaseUISchema {
           {'label': gettext('IDENTITY'), 'value': 'i'},
         ];
 
-        if (this.nodeInfo && this.nodeInfo.server &&
-            this.nodeInfo.server.version >= 120000) {
+        if (this.getServerVersion() >= 120000) {
           // You can't change the existing column to Generated column.
           if (this.isNew(state)) {
             options.push({
@@ -529,15 +531,18 @@ export default class ColumnSchema extends BaseUISchema {
       ], null, null, ['name', 'value']),
       uniqueCol : ['name'], mode: ['edit', 'create'],
       canAdd: true, canEdit: false, canDelete: true,
-    }, {
+    },{
+      id: 'security', label: gettext('Security'), type: 'group',
+      visible: !this.inErd,
+    },{
       id: 'attacl', label: gettext('Privileges'), type: 'collection',
-      group: gettext('Security'),
+      group: 'security',
       schema: this.getPrivilegeRoleSchema(['a','r','w','x']),
       mode: ['edit'], canAdd: true, canDelete: true,
       uniqueCol : ['grantee'],
     },{
       id: 'seclabels', label: gettext('Security labels'), canAdd: true,
-      schema: new SecLabelSchema(), group: gettext('Security'),
+      schema: new SecLabelSchema(), group: 'security',
       mode: ['edit', 'create'], editable: false, type: 'collection',
       min_version: 90100, canEdit: false, canDelete: true,
       uniqueCol : ['provider'],
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/foreign_key/static/js/foreign_key.ui.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/foreign_key/static/js/foreign_key.ui.js
index 5903f5394..2dffa5f02 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/foreign_key/static/js/foreign_key.ui.js
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/foreign_key/static/js/foreign_key.ui.js
@@ -86,7 +86,7 @@ class ForeignKeyHeaderSchema extends BaseUISchema {
   }
 }
 
-class ForeignKeyColumnSchema extends BaseUISchema {
+export class ForeignKeyColumnSchema extends BaseUISchema {
   constructor() {
     super({
       local_column: undefined,
@@ -111,7 +111,7 @@ class ForeignKeyColumnSchema extends BaseUISchema {
 }
 
 export default class ForeignKeySchema extends BaseUISchema {
-  constructor(fieldOptions={}, nodeInfo, getColumns, initData={}) {
+  constructor(fieldOptions={}, nodeInfo, getColumns, initValues={}, inErd=false) {
     super({
       name: undefined,
       reftab: undefined,
@@ -128,7 +128,7 @@ export default class ForeignKeySchema extends BaseUISchema {
       autoindex: true,
       coveringindex: undefined,
       hasindex:undefined,
-      ...initData,
+      ...initValues,
     });
 
     this.nodeInfo = nodeInfo;
@@ -136,7 +136,7 @@ export default class ForeignKeySchema extends BaseUISchema {
     this.fkHeaderSchema = new ForeignKeyHeaderSchema(fieldOptions, getColumns);
     this.fkHeaderSchema.fkObj = this;
     this.fkColumnSchema = new ForeignKeyColumnSchema();
-
+    this.inErd = inErd;
   }
 
   get idAttribute() {
@@ -240,9 +240,7 @@ export default class ForeignKeySchema extends BaseUISchema {
           return true;
         }
         // If we are in table edit mode then
-        if(obj.inTable) {
-          return true;
-        } else if(state.hasindex) {
+        if(state.hasindex) {
           return true;
         }
         return false;
@@ -252,7 +250,7 @@ export default class ForeignKeySchema extends BaseUISchema {
           return {};
         }
         // If we are in table edit mode
-        if(obj.inTable) {
+        if(obj.inTable && !this.inErd) {
           if(obj.isNew(state) && obj.top.isNew()) {
             return {autoindex: false, coveringindex: ''};
           }
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/static/js/table.ui.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/static/js/table.ui.js
index 94622e2b3..1290e6ce3 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/static/js/table.ui.js
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/static/js/table.ui.js
@@ -70,7 +70,7 @@ export function getNodeTableSchema(treeNodeInfo, itemNodeData, pgBrowser) {
 }
 
 export class ConstraintsSchema extends BaseUISchema {
-  constructor(nodeInfo, getFkObj, getExConsObj, otherOptions) {
+  constructor(nodeInfo, getFkObj, getExConsObj, otherOptions, inErd=false) {
     super();
     this.nodeInfo = nodeInfo;
     this.primaryKeyObj = new PrimaryKeySchema({
@@ -81,13 +81,16 @@ export class ConstraintsSchema extends BaseUISchema {
       spcname: otherOptions.spcname,
     }, nodeInfo);
     this.exConsObj = getExConsObj();
+    this.inErd = inErd;
   }
 
   changeColumnOptions(colOptions) {
     this.primaryKeyObj.changeColumnOptions(colOptions);
     this.fkObj.changeColumnOptions(colOptions);
-    this.uniqueConsObj.changeColumnOptions(colOptions);
-    this.exConsObj.changeColumnOptions(colOptions);
+    if(!this.inErd) {
+      this.uniqueConsObj.changeColumnOptions(colOptions);
+      this.exConsObj.changeColumnOptions(colOptions);
+    }
   }
 
   anyColumnAdded(state) {
@@ -147,20 +150,24 @@ export class ConstraintsSchema extends BaseUISchema {
           return {foreign_key: []};
         }
       }
+    },{
+      id: 'check_group', type: 'group', label: gettext('Check'), visible: !this.inErd,
     },{
       id: 'check_constraint', label: '',
       schema: new CheckConstraintSchema(),
       editable: false, type: 'collection',
-      group: gettext('Check'), mode: ['edit', 'create'],
+      group: 'check_group', mode: ['edit', 'create'],
       canEdit: true, canDelete: true, deps:['is_partitioned'],
       canAdd: true,
       columns : ['name', 'consrc'],
       disabled: this.inCatalog,
+    },{
+      id: 'unique_group', type: 'group', label: gettext('Unique'), visible: !this.inErd,
     },{
       id: 'unique_constraint', label: '',
       schema: this.uniqueConsObj,
       editable: false, type: 'collection',
-      group: gettext('Unique'), mode: ['edit', 'create'],
+      group: 'unique_group', mode: ['edit', 'create'],
       canEdit: true, canDelete: true, deps:['is_partitioned', 'typname'],
       columns : ['name', 'columns'],
       disabled: this.inCatalog,
@@ -176,11 +183,13 @@ export class ConstraintsSchema extends BaseUISchema {
           return {unique_constraint: []};
         }
       }
+    },{
+      id: 'exclude_group', type: 'group', label: gettext('Exclude'), visible: !this.inErd,
     },{
       id: 'exclude_constraint', label: '',
       schema: this.exConsObj,
       editable: false, type: 'collection',
-      group: gettext('Exclude'), mode: ['edit', 'create'],
+      group: 'exclude_group', mode: ['edit', 'create'],
       canEdit: true, canDelete: true, deps:['is_partitioned'],
       columns : ['name', 'columns', 'constraint'],
       disabled: this.inCatalog,
@@ -276,7 +285,7 @@ export class LikeSchema extends BaseUISchema {
 
 export default class TableSchema extends BaseUISchema {
   constructor(fieldOptions={}, nodeInfo, schemas={}, getPrivilegeRoleSchema=()=>{}, getColumns=()=>[],
-    getCollations=()=>[], getOperatorClass=()=>[], getAttachTables=()=>[], initValues={}) {
+    getCollations=()=>[], getOperatorClass=()=>[], getAttachTables=()=>[], initValues={}, inErd=false) {
     super({
       name: undefined,
       oid: undefined,
@@ -307,6 +316,7 @@ export default class TableSchema extends BaseUISchema {
       autovacuum_enabled: 'x',
       primary_key: [],
       foreign_key: [],
+      partition_keys: [],
       partitions: [],
       partition_type: 'range',
       is_partitioned: false,
@@ -325,6 +335,24 @@ export default class TableSchema extends BaseUISchema {
     this.columnsSchema = this.schemas.columns && this.schemas.columns() || {};
     this.vacuumSettingsSchema = this.schemas.vacuum_settings && this.schemas.vacuum_settings() || {};
     this.partitionKeysObj = new PartitionKeysSchema([], getCollations, getOperatorClass);
+    this.inErd = inErd;
+  }
+
+  static getErdSupportedData(data) {
+    let newData = {...data};
+    const SUPPORTED_KEYS = [
+      'name', 'schema', 'description', 'rlspolicy', 'forcerlspolicy', 'fillfactor',
+      'toast_tuple_target', 'parallel_workers', 'relhasoids', 'relpersistence',
+      'columns', 'primary_key', 'foreign_key',
+    ];
+    newData = _.pick(newData, SUPPORTED_KEYS);
+
+    /* Remove inherited references */
+    newData.columns = newData.columns.map((c)=>{
+      delete c.inheritedfromtable;
+      return c;
+    });
+    return newData;
   }
 
   get idAttribute() {
@@ -397,9 +425,9 @@ export default class TableSchema extends BaseUISchema {
       id: 'oid', label: gettext('OID'), type: 'text', mode: ['properties'],
     },{
       id: 'relowner', label: gettext('Owner'), type: 'select',
-      options: this.fieldOptions.relowner, noEmpty: true,
+      options: this.fieldOptions.relowner, noEmpty: this.inErd ? false : true,
       mode: ['properties', 'create', 'edit'], controlProps: {allowClear: false},
-      readonly: this.inCatalog,
+      readonly: this.inCatalog, visible: !this.inErd,
     },{
       id: 'schema', label: gettext('Schema'), type: 'select',
       options: this.fieldOptions.schema, noEmpty: true,
@@ -407,7 +435,7 @@ export default class TableSchema extends BaseUISchema {
       readonly: this.inCatalog,
     },{
       id: 'spcname', label: gettext('Tablespace'),
-
+      visible: !this.inErd,
       mode: ['properties', 'create', 'edit'], deps: ['is_partitioned'],
       readonly: this.inCatalog, type: (state)=>{
         return {
@@ -421,6 +449,9 @@ export default class TableSchema extends BaseUISchema {
       id: 'partition', type: 'group', label: gettext('Partitions'),
       mode: ['edit', 'create'], min_version: 100000,
       visible: function(state) {
+        if(this.inErd) {
+          return false;
+        }
         // Always show in case of create mode
         if (obj.isNew(state) || state.is_partitioned)
           return true;
@@ -429,7 +460,7 @@ export default class TableSchema extends BaseUISchema {
     },{
       id: 'is_partitioned', label:gettext('Partitioned table?'), cell: 'switch',
       type: 'switch', mode: ['properties', 'create', 'edit'],
-      min_version: 100000,
+      min_version: 100000, visible: !this.inErd,
       readonly: function(state) {
         if (!obj.isNew(state))
           return true;
@@ -447,7 +478,7 @@ export default class TableSchema extends BaseUISchema {
       type: 'select', group: gettext('Columns'),
       deps: ['typname', 'is_partitioned'], mode: ['create', 'edit'],
       controlProps: { multiple: true, allowClear: false, placeholder: gettext('Select to inherit from...')},
-      options: this.fieldOptions.coll_inherits,
+      options: this.fieldOptions.coll_inherits, visible: !this.inErd,
       optionsLoaded: (res)=>obj.inheritedTableList=res,
       disabled: (state)=>{
         if(state.adding_inherit_cols || state.is_partitioned){
@@ -581,7 +612,18 @@ export default class TableSchema extends BaseUISchema {
       deps: ['typname', 'is_partitioned'],
       depChange: (state, source, topState, actionObj)=>{
         if(source[0] === 'columns') {
-          obj.changeColumnOptions(state.columns);
+          /* In ERD, attnum is an imp var for setting the links
+          Here, attnum is set to max avail value.
+          */
+          let columns = state.columns;
+          if(actionObj.type === SCHEMA_STATE_ACTIONS.ADD_ROW && this.inErd) {
+            let lastAttnum = _.maxBy(columns, (c)=>c.attnum)?.attnum;
+            if(_.isUndefined(lastAttnum) || _.isNull(lastAttnum)) {
+              lastAttnum = -1;
+            }
+            columns[columns.length-1].attnum = lastAttnum + 1;
+          }
+          obj.changeColumnOptions(columns);
           /* If primary key switch changes, primary key collection need to change */
           if(actionObj.path.indexOf('is_primary_key') > -1) {
             let tabColPath = _.slice(actionObj.path, 0, -1);
@@ -631,6 +673,7 @@ export default class TableSchema extends BaseUISchema {
     },{
       id: 'typname', label: gettext('Of type'), type: 'select',
       mode: ['properties', 'create', 'edit'], group: 'advanced', deps: ['coll_inherits'],
+      visible: !this.inErd,
       disabled: (state)=>{
         if(!obj.inSchemaWithModelCheck(state) && isEmptyString(state.coll_inherits)) {
           return false;
@@ -743,6 +786,7 @@ export default class TableSchema extends BaseUISchema {
       type: 'nested-fieldset', label: gettext('Like'),
       group: 'advanced', mode: ['create'],
       schema: new LikeSchema(this.fieldOptions.like_relation),
+      visible: !this.inErd,
     },{
       id: 'partition_type', label:gettext('Partition Type'),
       editable: false, type: 'select', controlProps: {allowClear: false},
@@ -774,6 +818,7 @@ export default class TableSchema extends BaseUISchema {
       id: 'partition_keys', label:gettext('Partition Keys'),
       schema: obj.partitionKeysObj,
       editable: true, type: 'collection',
+      columns: ['key_type', 'pt_column', 'expression'].concat(!this.inErd ? ['collationame', 'op_class'] : []),
       group: 'partition', mode: ['create'],
       deps: ['is_partitioned', 'partition_type', 'typname'],
       canEdit: false, canDelete: true,
@@ -885,28 +930,32 @@ export default class TableSchema extends BaseUISchema {
         '</li></ul>',
       ].join(''),
       min_version: 100000,
-    },
-    {
+    },{
+      type: 'group', id: 'parameters', label: gettext('Parameters'),
+      visible: !this.inErd,
+    },{
       // Here - we will create tab control for storage parameters
       // (auto vacuum).
-      type: 'nested-tab', group: gettext('Parameters'),
+      type: 'nested-tab', group: 'parameters',
       mode: ['edit', 'create'], deps: ['is_partitioned'],
-      schema: this.vacuumSettingsSchema,
+      schema: this.vacuumSettingsSchema, visible: !this.inErd,
+    },{
+      id: 'security_group', type: 'group', label: gettext('Security'), visible: !this.inErd,
     },
     {
       id: 'relacl_str', label: gettext('Privileges'), disabled: this.inCatalog,
-      type: 'text', mode: ['properties'], group: gettext('Security'),
+      type: 'text', mode: ['properties'], group: 'security_group',
     },
     {
       id: 'relacl', label: gettext('Privileges'), type: 'collection',
-      group: gettext('Security'), schema: this.getPrivilegeRoleSchema(['a','r','w','d','D','x','t']),
+      group: 'security_group', schema: this.getPrivilegeRoleSchema(['a','r','w','d','D','x','t']),
       mode: ['edit', 'create'], canAdd: true, canDelete: true,
       uniqueCol : ['grantee'],
     },{
       id: 'seclabels', label: gettext('Security labels'), canEdit: false,
       schema: new SecLabelSchema(), editable: false, canAdd: true,
       type: 'collection', min_version: 90100, mode: ['edit', 'create'],
-      group: gettext('Security'), canDelete: true, control: 'unique-col-collection',
+      group: 'security_group', canDelete: true, control: 'unique-col-collection',
     },{
       id: 'vacuum_settings_str', label: gettext('Storage settings'),
       type: 'multiline', group: 'advanced', mode: ['properties'],
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/utils.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/utils.py
index e0099396e..9f370a951 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/utils.py
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/utils.py
@@ -1125,7 +1125,7 @@ class BaseTableView(PGChildNodeView, BasePartitionTable, VacuumSettings):
         elif part_type in data and data[part_type] == 'hash':
             partition_scheme = 'HASH ('
 
-        for row in data[part_keys]:
+        for row in data.get(part_keys, []):
             if row['key_type'] == 'column':
                 partition_scheme += self.qtIdent(
                     self.conn, row['pt_column'])
@@ -1141,7 +1141,7 @@ class BaseTableView(PGChildNodeView, BasePartitionTable, VacuumSettings):
                 partition_scheme += row['expression'] + ', '
 
         # Remove extra space and comma
-        if len(data[part_keys]) > 0:
+        if len(data.get(part_keys, [])) > 0:
             partition_scheme = partition_scheme[:-2]
         partition_scheme += ')'
 
diff --git a/web/pgadmin/static/js/SchemaView/FormView.jsx b/web/pgadmin/static/js/SchemaView/FormView.jsx
index 17371202e..74fa2bb2a 100644
--- a/web/pgadmin/static/js/SchemaView/FormView.jsx
+++ b/web/pgadmin/static/js/SchemaView/FormView.jsx
@@ -205,6 +205,13 @@ export default function FormView({
 
     if(modeSupported) {
       let {group, CustomControl} = field;
+      if(field.type === 'group') {
+        groupLabels[field.id] = field.label;
+        if(!visible) {
+          schemaRef.current.filterGroups.push(field.label);
+        }
+        return;
+      }
       group = groupLabels[group] || group || defaultTab;
 
       if(!tabs[group]) tabs[group] = [];
@@ -261,11 +268,6 @@ export default function FormView({
         } else {
           tabs[group].push(<DataGridView {...props}/>);
         }
-      } else if(field.type === 'group') {
-        groupLabels[field.id] = field.label;
-        if(!visible) {
-          schemaRef.current.filterGroups.push(field.label);
-        }
       } else {
         /* Its a form control */
         const hasError = _.isEqual(accessPath.concat(field.id), stateUtils.formErr.name);
diff --git a/web/pgadmin/static/js/SchemaView/index.jsx b/web/pgadmin/static/js/SchemaView/index.jsx
index 0f3073e9e..d78ba7a7b 100644
--- a/web/pgadmin/static/js/SchemaView/index.jsx
+++ b/web/pgadmin/static/js/SchemaView/index.jsx
@@ -89,7 +89,8 @@ function isValueEqual(val1, val2) {
   /* If the orig value and new value are of different datatype but of same value(numeric) "no change" */
   /* If the orig value is undefined or null and new value is boolean false "no change" */
   if ((_.isEqual(val1, val2)
-    || ((val1 === null || _.isUndefined(val1)) && !val2)
+    || ((val1 === null || _.isUndefined(val1)) && val2 === '')
+    || ((val1 === null || _.isUndefined(val1)) && typeof(val2) === 'boolean' && !val2)
     || (attrDefined ? _.isEqual(val1.toString(), val2.toString()) : false
     ))) {
     return true;
@@ -98,22 +99,6 @@ function isValueEqual(val1, val2) {
   }
 }
 
-function objectComparator(obj1, obj2) {
-  for(const key of _.union(Object.keys(obj1), Object.keys(obj2))) {
-    let equal = isValueEqual(obj1[key], obj2[key]);
-    if(equal) {
-      continue;
-    } else {
-      return false;
-    }
-  }
-  return true;
-}
-
-const diffArrayOptions = {
-  compareFunction: objectComparator,
-};
-
 function getChangedData(topSchema, viewHelperProps, sessData, stringify=false, includeSkipChange=true) {
   let changedData = {};
   let isEdit = viewHelperProps.mode === 'edit';
@@ -173,13 +158,13 @@ function getChangedData(topSchema, viewHelperProps, sessData, stringify=false, i
             );
             change = {};
             if(changeDiff.added.length > 0) {
-              change['added'] = cleanCid(changeDiff.added);
+              change['added'] = cleanCid(changeDiff.added, viewHelperProps.keepCid);
             }
             if(changeDiff.removed.length > 0) {
               change['deleted'] = cleanCid(changeDiff.removed.map((row)=>{
                 /* Deleted records should be original, not the changed */
                 return _.find(_.get(origVal, field.id), ['cid', row.cid]);
-              }));
+              }), viewHelperProps.keepCid);
             }
             if(changeDiff.updated.length > 0) {
               /* There is change in collection. Parse further to go deep */
@@ -204,7 +189,7 @@ function getChangedData(topSchema, viewHelperProps, sessData, stringify=false, i
                   });
                 }
               }
-              change['changed'] = cleanCid(change['changed']);
+              change['changed'] = cleanCid(change['changed'], viewHelperProps.keepCid);
             }
             if(Object.keys(change).length > 0) {
               attrChanged(field.id, change, true);
@@ -214,21 +199,18 @@ function getChangedData(topSchema, viewHelperProps, sessData, stringify=false, i
           }
         } else if(!isEdit) {
           if(field.type === 'collection') {
-            /* For fixed rows, check the updated changes */
-            if(!_.isUndefined(field.fixedRows)) {
-              const changeDiff = diffArray(
-                _.get(origVal, field.id) || [],
-                _.get(sessVal, field.id) || [],
-                'cid',
-                diffArrayOptions
-              );
-              if(changeDiff.updated.length > 0) {
-                let change = cleanCid(_.get(sessVal, field.id));
-                attrChanged(field.id, change, true);
-              }
-            } else {
-              let change = cleanCid(_.get(sessVal, field.id));
-              attrChanged(field.id, change);
+            const changeDiff = diffArray(
+              _.get(origVal, field.id) || [],
+              _.get(sessVal, field.id) || [],
+              'cid',
+            );
+            /* For fixed rows, check only the updated changes */
+            if((!_.isUndefined(field.fixedRows) && changeDiff.updated.length > 0)
+              || (_.isUndefined(field.fixedRows) && (
+                changeDiff.added.length > 0 || changeDiff.removed.length > 0 || changeDiff.updated.length > 0
+              ))) {
+              let change = cleanCid(_.get(sessVal, field.id), viewHelperProps.keepCid);
+              attrChanged(field.id, change, true);
             }
           } else {
             attrChanged(field.id);
@@ -409,18 +391,18 @@ const sessDataReducer = (state, action)=>{
 };
 
 /* Remove cid key added by prepareData */
-function cleanCid(coll) {
-  if(!coll) {
+function cleanCid(coll, keepCid=false) {
+  if(!coll || keepCid) {
     return coll;
   }
   return coll.map((o)=>_.pickBy(o, (v, k)=>k!='cid'));
 }
 
-function prepareData(val) {
+function prepareData(val, createMode=false) {
   if(_.isPlainObject(val)) {
     _.forIn(val, function (el) {
       if (_.isObject(el)) {
-        prepareData(el);
+        prepareData(el, createMode);
       }
     });
   } else if(_.isArray(val)) {
@@ -432,8 +414,8 @@ function prepareData(val) {
         So to decide whether row is new or not set, the cid starts with
         nn (not new) for existing rows. Newly added will start with 'c' (created)
         */
-        el['cid'] = _.uniqueId('nn');
-        prepareData(el);
+        el['cid'] = createMode ? _.uniqueId('c') : _.uniqueId('nn');
+        prepareData(el, createMode);
       }
     });
   }
@@ -532,7 +514,7 @@ function SchemaDialogView({
       });
     } else {
       /* Use the defaults as the initital data */
-      schema.origData = prepareData(schema.defaults);
+      schema.origData = prepareData(schema.defaults, true);
       schema.initialise(schema.origData);
       sessDispatch({
         type: SCHEMA_STATE_ACTIONS.INIT,
@@ -624,6 +606,7 @@ function SchemaDialogView({
           );
         }
       }).catch((err)=>{
+        console.error(err);
         setFormErr({
           name: 'apierror',
           message: parseApiError(err),
diff --git a/web/pgadmin/static/js/Theme/index.jsx b/web/pgadmin/static/js/Theme/index.jsx
index b27692875..3a0118802 100644
--- a/web/pgadmin/static/js/Theme/index.jsx
+++ b/web/pgadmin/static/js/Theme/index.jsx
@@ -106,23 +106,6 @@ basicSettings = createMuiTheme(basicSettings, {
         paddingRight: basicSettings.spacing(1.5),
       }
     },
-    MuiToggleButton: {
-      root: {
-        textTransform: 'none,',
-        padding: basicSettings.spacing(0.5, 2.5, 0.5, 0.5),
-        color: 'abc',
-        '&:hover':{
-          backgroundColor: 'abc',
-        },
-        '&$selected': {
-          color: 'abc',
-          backgroundColor: 'abc',
-          '&:hover':{
-            backgroundColor: 'abc',
-          }
-        }
-      }
-    },
     MuiAccordion: {
       root: {
         boxShadow: 'none',
@@ -172,6 +155,17 @@ basicSettings = createMuiTheme(basicSettings, {
       body1: {
         fontSize: '1em',
       }
+    },
+    MuiDialog: {
+      paper: {
+        margin: 0,
+      }
+    },
+    MuiTooltip: {
+      popper: {
+        top: 0,
+        zIndex: 9999,
+      }
     }
   },
   transitions: {
@@ -374,6 +368,7 @@ function getFinalTheme(baseTheme) {
       },
       MuiToggleButton: {
         root: {
+          padding: 'abc',
           paddingRight: baseTheme.spacing(2.5),
           paddingLeft: baseTheme.spacing(0.5),
           color: 'abc',
diff --git a/web/pgadmin/static/scss/_alertify.overrides.scss b/web/pgadmin/static/scss/_alertify.overrides.scss
index 40f6ac383..ddaaee18d 100644
--- a/web/pgadmin/static/scss/_alertify.overrides.scss
+++ b/web/pgadmin/static/scss/_alertify.overrides.scss
@@ -42,7 +42,7 @@
     }
 
     & .ajs-handle {
-      z-index: 5;
+      z-index: 1020;
     }
   }
 
diff --git a/web/pgadmin/tools/erd/__init__.py b/web/pgadmin/tools/erd/__init__.py
index 6d16cbd79..6978d5db1 100644
--- a/web/pgadmin/tools/erd/__init__.py
+++ b/web/pgadmin/tools/erd/__init__.py
@@ -532,6 +532,35 @@ def prequisite(trans_id, sgid, sid, did):
     )
 
 
+def translate_foreign_keys(tab_fks, tab_data, all_nodes):
+    """
+    This function will take the from table foreign keys and translate
+    it into non oid based format. It will allow creating FK sql even
+    if table is not already created.
+    :param tab_fks: Table foreign keyss
+    :param tab_data: Table data
+    :param all_nodes: All the nodes info from ERD
+    :return: Translated foreign key data
+    """
+    for tab_fk in tab_fks:
+        if 'columns' not in tab_fk:
+            continue
+        print(tab_data)
+        remote_table = all_nodes[tab_fk['columns'][0]['references']]
+        tab_fk['schema'] = tab_data['schema']
+        tab_fk['table'] = tab_data['name']
+        tab_fk['remote_schema'] = remote_table['schema']
+        tab_fk['remote_table'] = remote_table['name']
+
+        new_column = {
+            'local_column': tab_fk['columns'][0]['local_column'],
+            'referenced': tab_fk['columns'][0]['referenced']
+        }
+        tab_fk['columns'][0] = new_column
+
+    return tab_fks
+
+
 @blueprint.route('/sql/<int:trans_id>/<int:sgid>/<int:sid>/<int:did>',
                  methods=["POST"],
                  endpoint='sql')
@@ -542,12 +571,16 @@ def sql(trans_id, sgid, sid, did):
     conn = _get_connection(sid, did, trans_id)
 
     sql = ''
-    for tab_key, tab_data in data.get('nodes', {}).items():
+    tab_foreign_keys = []
+    all_nodes = data.get('nodes', {})
+    for tab_key, tab_data in all_nodes.items():
+        tab_fks = tab_data.pop('foreign_key', [])
+        tab_foreign_keys.extend(translate_foreign_keys(tab_fks, tab_data, all_nodes))
         sql += '\n\n' + helper.get_table_sql(tab_data)
 
-    for link_key, link_data in data.get('links', {}).items():
-        link_sql, name = fkey_utils.get_sql(conn, link_data, None)
-        sql += '\n\n' + link_sql
+    for tab_fk in tab_foreign_keys:
+        fk_sql, name = fkey_utils.get_sql(conn, tab_fk, None)
+        sql += '\n\n' + fk_sql
 
     return make_json_response(
         data=sql,
diff --git a/web/pgadmin/tools/erd/static/js/erd_tool/ERDCore.js b/web/pgadmin/tools/erd/static/js/erd_tool/ERDCore.js
index 23b592149..b63b1786a 100644
--- a/web/pgadmin/tools/erd/static/js/erd_tool/ERDCore.js
+++ b/web/pgadmin/tools/erd/static/js/erd_tool/ERDCore.js
@@ -13,11 +13,16 @@
 import createEngine from '@projectstorm/react-diagrams';
 import {DagreEngine, PathFindingLinkFactory, PortModelAlignment} from '@projectstorm/react-diagrams';
 import { ZoomCanvasAction } from '@projectstorm/react-canvas-core';
+import _ from 'lodash';
 
 import {TableNodeFactory, TableNodeModel } from './nodes/TableNode';
 import {OneToManyLinkFactory, OneToManyLinkModel } from './links/OneToManyLink';
 import { OneToManyPortFactory } from './ports/OneToManyPort';
 import ERDModel from './ERDModel';
+import ForeignKeySchema from '../../../../../browser/server_groups/servers/databases/schemas/tables/constraints/foreign_key/static/js/foreign_key.ui';
+import diffArray from 'diff-arrays-of-objects';
+import TableSchema from '../../../../../browser/server_groups/servers/databases/schemas/tables/static/js/table.ui';
+import ColumnSchema from '../../../../../browser/server_groups/servers/databases/schemas/tables/columns/static/js/column.ui';
 
 export default class ERDCore {
   constructor() {
@@ -66,8 +71,8 @@ export default class ERDCore {
           else if(e.function === 'showNote') {
             this.fireEvent({node: e.entity}, 'showNote', true);
           }
-          else if(e.function === 'editNode') {
-            this.fireEvent({node: e.entity}, 'editNode', true);
+          else if(e.function === 'editTable') {
+            this.fireEvent({node: e.entity}, 'editTable', true);
           }
           else if(e.function === 'nodeUpdated') {
             this.fireEvent({}, 'nodesUpdated', true);
@@ -232,6 +237,188 @@ export default class ERDCore {
     return newLink;
   }
 
+  removePortLinks(port) {
+    let links = port.getLinks();
+    Object.values(links).forEach((link)=>{
+      link.getTargetPort().remove();
+      link.getSourcePort().remove();
+      link.setSelected(false);
+      link.remove();
+    });
+  }
+
+  syncTableLinks(tableNode, oldTableData) {
+    let tableData = tableNode.getData();
+    let tableNodesDict = this.getModel().getNodesDict();
+
+    const addLink = (theFk)=>{
+      let newData = {
+        local_table_uid: tableNode.getID(),
+        local_column_attnum: undefined,
+        referenced_table_uid: theFk.references,
+        referenced_column_attnum: undefined,
+      };
+      let sourceNode = tableNodesDict[newData.referenced_table_uid];
+
+      newData.local_column_attnum = _.find(tableNode.getColumns(), (col)=>col.name==theFk.local_column).attnum;
+      newData.referenced_column_attnum = _.find(sourceNode.getColumns(), (col)=>col.name==theFk.referenced).attnum;
+
+      this.addLink(newData, 'onetomany');
+    };
+
+    const removeLink = (theFk)=>{
+      let attnum = _.find(tableNode.getColumns(), (col)=>col.name==theFk.local_column).attnum;
+      let existPort = tableNode.getPort(tableNode.getPortName(attnum));
+      if(existPort && existPort.getSubtype() == 'many') {
+        existPort.removeAllLinks();
+        tableNode.removePort(existPort);
+      }
+    };
+
+    const changeDiff = diffArray(
+      oldTableData?.foreign_key || [],
+      tableData?.foreign_key || [],
+      'cid'
+    );
+
+    changeDiff.added.forEach((theFk)=>{
+      addLink(theFk.columns[0]);
+    });
+    changeDiff.removed.forEach((theFk)=>{
+      removeLink(theFk.columns[0]);
+    });
+
+    if(changeDiff.updated.length > 0) {
+      for(const changedRow of changeDiff.updated) {
+        let rowIndx = _.findIndex(tableData.foreign_key, (f)=>f.cid==changedRow.cid);
+        const changeDiffCols = diffArray(
+          oldTableData.foreign_key[rowIndx].columns,
+          tableData.foreign_key[rowIndx].columns,
+          'cid'
+        );
+        if(changeDiffCols.removed.length > 0 || changeDiffCols.added.length > 0) {
+          removeLink(changeDiffCols.removed[0]);
+          addLink(changeDiffCols.added[0]);
+        }
+      }
+    }
+  }
+
+  addOneToManyLink(onetomanyData) {
+    let newFk = new ForeignKeySchema({}, {}, ()=>{}, {autoindex: false});
+    let tableNodesDict = this.getModel().getNodesDict();
+    let fkColumn = {};
+    let sourceNode = tableNodesDict[onetomanyData.referenced_table_uid];
+    let targetNode = tableNodesDict[onetomanyData.local_table_uid];
+
+    fkColumn.local_column = _.find(targetNode.getColumns(), (col)=>col.attnum==onetomanyData.local_column_attnum).name;
+    fkColumn.referenced = _.find(sourceNode.getColumns(), (col)=>col.attnum==onetomanyData.referenced_column_attnum).name;
+    fkColumn.references = onetomanyData.referenced_table_uid;
+    fkColumn.references_table_name = sourceNode.getData().name;
+
+    let tableData = targetNode.getData();
+    tableData.foreign_key = tableData.foreign_key || [];
+
+    let col = newFk.fkColumnSchema.getNewData(fkColumn);
+    tableData.foreign_key.push(
+      newFk.getNewData({
+        columns: [col],
+      })
+    );
+    targetNode.setData(tableData);
+    let newLink = this.addLink(onetomanyData, 'onetomany');
+    this.clearSelection();
+    newLink.setSelected(true);
+    this.repaint();
+  }
+
+  removeOneToManyLink(link) {
+    let linkData = link.getData();
+    let tableNode = this.getModel().getNodesDict()[linkData.local_table_uid];
+    let tableData = tableNode.getData();
+
+    let newForeingKeys = [];
+    tableData.foreign_key?.forEach((theFkRow)=>{
+      let theFk = theFkRow.columns[0];
+      let attnum = _.find(tableNode.getColumns(), (col)=>col.name==theFk.local_column).attnum;
+      /* Skip all those whose attnum matches to the link */
+      if(linkData.local_column_attnum != attnum) {
+        newForeingKeys.push(theFkRow);
+      }
+    });
+    tableData.foreign_key = newForeingKeys;
+    tableNode.setData(tableData);
+    link.getTargetPort().remove();
+    link.getSourcePort().remove();
+    link.setSelected(false);
+    link.remove();
+  }
+
+  addManyToManyLink(manytomanyData) {
+    let nodes = this.getModel().getNodesDict();
+    let leftNode = nodes[manytomanyData.left_table_uid];
+    let rightNode = nodes[manytomanyData.right_table_uid];
+
+    let tableObj = new TableSchema({}, {}, {
+      constraints:()=>{},
+      columns:()=>new ColumnSchema(()=>{}, {}, {}, {}),
+      vacuum_settings:()=>{},
+    }, ()=>{}, ()=>{}, ()=>{}, ()=>{});
+
+    let tableData = tableObj.getNewData({
+      name: `${leftNode.getData().name}_${rightNode.getData().name}`,
+      schema: leftNode.getData().schema,
+      columns: [tableObj.columnsSchema.getNewData({
+        ...leftNode.getColumnAt(manytomanyData.left_table_column_attnum),
+        'name': `${leftNode.getData().name}_${leftNode.getColumnAt(manytomanyData.left_table_column_attnum).name}`,
+        'attnum': 0,
+        'is_primary_key': false,
+      }),tableObj.columnsSchema.getNewData({
+        ...rightNode.getColumnAt(manytomanyData.right_table_column_attnum),
+        'name': `${rightNode.getData().name}_${rightNode.getColumnAt(manytomanyData.right_table_column_attnum).name}`,
+        'attnum': 1,
+        'is_primary_key': false,
+      })],
+    });
+
+    // let tableData = {
+    //   name: `${leftNode.getData().name}_${rightNode.getData().name}`,
+    //   schema: leftNode.getData().schema,
+    //   columns: [{
+    //     ...leftNode.getColumnAt(manytomanyData.left_table_column_attnum),
+    //     'name': `${leftNode.getData().name}_${leftNode.getColumnAt(manytomanyData.left_table_column_attnum).name}`,
+    //     'is_primary_key': false,
+    //     'attnum': 0,
+    //   },{
+    //     ...rightNode.getColumnAt(manytomanyData.right_table_column_attnum),
+    //     'name': `${rightNode.getData().name}_${rightNode.getColumnAt(manytomanyData.right_table_column_attnum).name}`,
+    //     'is_primary_key': false,
+    //     'attnum': 1,
+    //   }],
+    // };
+    let newNode = this.addNode(tableData);
+    this.clearSelection();
+    newNode.setSelected(true);
+
+    let linkData = {
+      local_table_uid: newNode.getID(),
+      local_column_attnum: newNode.getColumns()[0].attnum,
+      referenced_table_uid: manytomanyData.left_table_uid,
+      referenced_column_attnum : manytomanyData.left_table_column_attnum,
+    };
+    this.addOneToManyLink(linkData);
+
+    linkData = {
+      local_table_uid: newNode.getID(),
+      local_column_attnum: newNode.getColumns()[1].attnum,
+      referenced_table_uid: manytomanyData.right_table_uid,
+      referenced_column_attnum : manytomanyData.right_table_column_attnum,
+    };
+    this.addOneToManyLink(linkData);
+
+    this.repaint();
+  }
+
   serialize(version) {
     return {
       version: version||0,
@@ -246,65 +433,53 @@ export default class ERDCore {
   }
 
   serializeData() {
-    let nodes = {}, links = {};
+    let nodes = {};
     let nodesDict = this.getModel().getNodesDict();
 
     Object.keys(nodesDict).forEach((id)=>{
       nodes[id] = nodesDict[id].serializeData();
     });
 
-    this.getModel().getLinks().map((link)=>{
-      links[link.getID()] = link.serializeData(nodesDict);
-    });
-
-    /* Separate the links from nodes so that we don't have any dependancy issues */
     return {
       'nodes': nodes,
-      'links': links,
     };
   }
 
   deserializeData(data){
     let oidUidMap = {};
-    let uidFks = [];
-    data.forEach((node)=>{
-      let newData = {
-        name: node.name,
-        schema: node.schema,
-        description: node.description,
-        columns: node.columns,
-        primary_key: node.primary_key,
-      };
-      let newNode = this.addNode(newData);
-      oidUidMap[node.oid] = newNode.getID();
-      if(node.foreign_key) {
-        node.foreign_key.forEach((a_fk)=>{
-          uidFks.push({
-            uid: newNode.getID(),
-            data: a_fk.columns[0],
-          });
-        });
-      }
+
+    /* Add the nodes */
+    data.forEach((nodeData)=>{
+      let newNode = this.addNode(TableSchema.getErdSupportedData(nodeData));
+      oidUidMap[nodeData.oid] = newNode.getID();
     });
 
     /* Lets use the oidUidMap for creating the links */
-    uidFks.forEach((fkData)=>{
-      let tableNodesDict = this.getModel().getNodesDict();
-      let newData = {
-        local_table_uid: fkData.uid,
-        local_column_attnum: undefined,
-        referenced_table_uid: oidUidMap[fkData.data.references],
-        referenced_column_attnum: undefined,
-      };
-
-      let sourceNode = tableNodesDict[newData.referenced_table_uid];
-      let targetNode = tableNodesDict[newData.local_table_uid];
-
-      newData.local_column_attnum = _.find(targetNode.getColumns(), (col)=>col.name==fkData.data.local_column).attnum;
-      newData.referenced_column_attnum = _.find(sourceNode.getColumns(), (col)=>col.name==fkData.data.referenced).attnum;
-
-      this.addLink(newData, 'onetomany');
+    let tableNodesDict = this.getModel().getNodesDict();
+    _.forIn(tableNodesDict, (node, uid)=>{
+      let nodeData = node.getData();
+      if(nodeData.foreign_key) {
+        nodeData.foreign_key.forEach((theFk)=>{
+          delete theFk.oid;
+          theFk = theFk.columns[0];
+          theFk.references = oidUidMap[theFk.references];
+          let newData = {
+            local_table_uid: uid,
+            local_column_attnum: undefined,
+            referenced_table_uid: theFk.references,
+            referenced_column_attnum: undefined,
+          };
+          let sourceNode = tableNodesDict[newData.referenced_table_uid];
+          let targetNode = tableNodesDict[newData.local_table_uid];
+
+          newData.local_column_attnum = _.find(targetNode.getColumns(), (col)=>col.name==theFk.local_column).attnum;
+          newData.referenced_column_attnum = _.find(sourceNode.getColumns(), (col)=>col.name==theFk.referenced).attnum;
+
+          this.addLink(newData, 'onetomany');
+        });
+      }
     });
+
     setTimeout(this.dagreDistributeNodes.bind(this), 250);
   }
 
diff --git a/web/pgadmin/tools/erd/static/js/erd_tool/dialogs/DialogWrapper.js b/web/pgadmin/tools/erd/static/js/erd_tool/dialogs/DialogWrapper.js
index cb0b1ff52..0ed761629 100644
--- a/web/pgadmin/tools/erd/static/js/erd_tool/dialogs/DialogWrapper.js
+++ b/web/pgadmin/tools/erd/static/js/erd_tool/dialogs/DialogWrapper.js
@@ -7,152 +7,98 @@
 //
 //////////////////////////////////////////////////////////////
 
-import gettext from 'sources/gettext';
-import * as commonUtils from 'sources/utils';
+import React from 'react';
+import ReactDOM from 'react-dom';
+import SchemaView from '../../../../../../static/js/SchemaView';
 
 export default class DialogWrapper {
-  constructor(dialogContainerSelector, dialogTitle, typeOfDialog,
-    jquery, pgBrowser, alertify, backform, backgrid) {
-
+  constructor(dialogContainerSelector, dialogTitle, typeOfDialog, alertify, serverInfo) {
     this.dialogContainerSelector = dialogContainerSelector;
     this.dialogTitle = dialogTitle;
-    this.jquery = jquery;
-    this.pgBrowser = pgBrowser;
     this.alertify = alertify;
-    this.backform = backform;
-    this.backgrid = backgrid;
     this.typeOfDialog = typeOfDialog;
+    this.serverInfo = serverInfo;
+
+    let self = this;
+    this.hooks = {
+      onshow: ()=>{
+        self.createDialog(self.elements.content);
+      },
+      onclose: ()=>{
+        self.cleanupDialog(self.elements.content);
+      }
+    };
   }
 
-  main(title, dialogModel, okCallback) {
+  main(title, dialogSchema, okCallback) {
     this.set('title', title);
-    this.dialogModel = dialogModel;
+    this.dialogSchema = dialogSchema;
     this.okCallback = okCallback;
   }
 
   build() {
-    this.alertify.pgDialogBuild.apply(this);
-  }
-
-  disableOKButton() {
-    this.__internal.buttons[1].element.disabled = true;
+    this.elements.dialog.classList.add('erd-dialog');
   }
 
-  enableOKButton() {
-    this.__internal.buttons[1].element.disabled = false;
-  }
-
-  focusOnDialog(alertifyDialog) {
-    let backform_tab = this.jquery(alertifyDialog.elements.body).find('.backform-tab');
-    backform_tab.attr('tabindex', -1);
-    this.pgBrowser.keyboardNavigation.getDialogTabNavigator(this.jquery(alertifyDialog.elements.dialog));
-    let container = backform_tab.find('.tab-content:first > .tab-pane.active:first');
-
-    if(container.length === 0 && alertifyDialog.elements.content.innerHTML) {
-      container = this.jquery(alertifyDialog.elements.content);
-    }
-    commonUtils.findAndSetFocus(container);
+  prepare() {
+    /* If tooltip is mounted after alertify in dom and button is click,
+    alertify re-positions itself on DOM to come in focus. This makes it lose
+    the button click events. Making it modal along with following fixes things. */
+    this.elements.modal.style.maxHeight=0;
+    this.elements.modal.style.maxWidth='none';
+    this.elements.modal.style.overflow='visible';
+    this.elements.dimmer.style.display='none';
   }
 
   setup() {
     return {
-      buttons: [{
-        text: gettext('Cancel'),
-        key: 27,
-        className: 'btn btn-secondary fa fa-lg fa-times pg-alertify-button',
-        'data-btn-name': 'cancel',
-      }, {
-        text: gettext('OK'),
-        key: 13,
-        className: 'btn btn-primary fa fa-lg fa-save pg-alertify-button',
-        'data-btn-name': 'ok',
-      }],
+      buttons: [],
       // Set options for dialog
       options: {
         title: this.dialogTitle,
         //disable both padding and overflow control.
         padding: !1,
         overflow: !1,
-        model: 0,
         resizable: true,
         maximizable: true,
         pinnable: false,
         closableByDimmer: false,
-        modal: false,
+        modal: true,
+        autoReset: false,
       },
     };
   }
 
-  prepare() {
-    const $container = this.jquery(this.dialogContainerSelector);
-    const dialog = this.createDialog($container);
-    dialog.render();
-    this.elements.content.innerHTML = '';
-    this.elements.content.appendChild($container.get(0));
-    this.jquery(this.elements.body.childNodes[0]).addClass(
-      'alertify_tools_dialog_properties obj_properties'
-    );
-    const statusBar = this.jquery(
-      '<div class=\'pg-prop-status-bar pg-prop-status-bar-absolute pg-el-xs-12 d-none\'>' +
-      '  <div class="error-in-footer"> ' +
-      '    <div class="d-flex px-2 py-1"> ' +
-      '      <div class="pr-2"> ' +
-      '        <i class="fa fa-exclamation-triangle text-danger" aria-hidden="true"></i> ' +
-      '      </div> ' +
-      '      <div class="alert-text" role="alert"></div> ' +
-      '       <div class="ml-auto close-error-bar"> ' +
-      '          <a aria-label="' + gettext('Close error bar') + '" class="close-error fa fa-times text-danger"></a> ' +
-      '        </div> ' +
-      '    </div> ' +
-      '  </div> ' +
-      '</div>').appendTo($container);
-
-    statusBar.find('.close-error').on('click', ()=>{
-      statusBar.addClass('d-none');
+  onSaveClick(isNew, data) {
+    return new Promise((resolve)=>{
+      this.okCallback(data);
+      this.close();
+      resolve();
     });
-
-    var onSessionInvalid = (msg) => {
-      statusBar.find('.alert-text').text(msg);
-      statusBar.removeClass('d-none');
-      this.disableOKButton();
-      return true;
-    };
-
-    var onSessionValidated = () => {
-      statusBar.find('.alert-text').text('');
-      statusBar.addClass('d-none');
-      this.enableOKButton();
-      return true;
-    };
-
-    this.dialogModel.on('pgadmin-session:valid', onSessionValidated);
-    this.dialogModel.on('pgadmin-session:invalid', onSessionInvalid);
-    this.dialogModel.startNewSession();
-    this.disableOKButton();
-    this.focusOnDialog(this);
   }
 
-  callback(event) {
-    if (this.wasOkButtonPressed(event)) {
-      this.okCallback(this.view.model.toJSON(true));
-    }
-  }
-
-  createDialog($container) {
-    let fields = this.backform.generateViewSchema(
-      null, this.dialogModel, 'create', null, null, true, null
-    );
-
-    this.view = new this.backform.Dialog({
-      el: $container,
-      model: this.dialogModel,
-      schema: fields,
-    });
-
-    return this.view;
+  createDialog(container) {
+    let self = this;
+    ReactDOM.render(
+      <SchemaView
+        formType={'dialog'}
+        getInitData={()=>Promise.resolve({})}
+        schema={this.dialogSchema}
+        viewHelperProps={{
+          mode: 'create',
+          keepCid: true,
+          serverInfo: this.serverInfo,
+        }}
+        onSave={this.onSaveClick.bind(this)}
+        onClose={()=>self.close()}
+        onDataChange={()=>{}}
+        hasSQL={false}
+        disableSqlHelp={true}
+        disableDialogHelp={true}
+      />, container);
   }
 
-  wasOkButtonPressed(event) {
-    return event.button['data-btn-name'] === 'ok';
+  cleanupDialog(container) {
+    ReactDOM.unmountComponentAtNode(container);
   }
 }
diff --git a/web/pgadmin/tools/erd/static/js/erd_tool/dialogs/ManyToManyDialog.js b/web/pgadmin/tools/erd/static/js/erd_tool/dialogs/ManyToManyDialog.js
index 5a35243ab..dc2421b7e 100644
--- a/web/pgadmin/tools/erd/static/js/erd_tool/dialogs/ManyToManyDialog.js
+++ b/web/pgadmin/tools/erd/static/js/erd_tool/dialogs/ManyToManyDialog.js
@@ -8,13 +8,48 @@
 //////////////////////////////////////////////////////////////
 
 import gettext from 'sources/gettext';
-import Backform from 'sources/backform.pgadmin';
 import Alertify from 'pgadmin.alertifyjs';
-import $ from 'jquery';
+import BaseUISchema from 'sources/SchemaView/base_schema.ui';
 
 import DialogWrapper from './DialogWrapper';
 import _ from 'lodash';
 
+class ManyToManySchema extends BaseUISchema {
+  constructor(fieldOptions={}, initValues={}) {
+    super({
+      left_table_uid: undefined,
+      left_table_column_attnum: undefined,
+      right_table_uid: undefined,
+      right_table_column_attnum: undefined,
+      ...initValues,
+    });
+    this.fieldOptions = fieldOptions;
+  }
+  get baseFields() {
+    return [{
+      id: 'left_table_uid', label: gettext('Local Table'),
+      type: 'select', readonly: true, controlProps: {allowClear: false},
+      options: this.fieldOptions.left_table_uid,
+    }, {
+      id: 'left_table_column_attnum', label: gettext('Local Column'),
+      type: 'select', options: this.fieldOptions.left_table_column_attnum,
+      controlProps: {allowClear: false}, noEmpty: true,
+    },{
+      id: 'right_table_uid', label: gettext('Referenced Table'),
+      type: 'select', options: this.fieldOptions.right_table_uid,
+      controlProps: {allowClear: false}, noEmpty: true,
+    },{
+      id: 'right_table_column_attnum', label: gettext('Referenced Column'),
+      controlProps: {allowClear: false}, deps: ['right_table_uid'],
+      type: (state)=>({
+        type: 'select',
+        options: state.right_table_uid ? ()=>this.fieldOptions.getRefColumns(state.right_table_uid) : [],
+        optionsReloadBasis: state.right_table_uid,
+      }),
+    }];
+  }
+}
+
 export default class ManyToManyDialog {
   constructor(pgBrowser) {
     this.pgBrowser = pgBrowser;
@@ -24,93 +59,29 @@ export default class ManyToManyDialog {
     return 'manytomany_dialog';
   }
 
-  getDataModel(attributes, tableNodesDict) {
-    const parseColumns = (columns)=>{
-      return columns.map((col)=>{
+  getUISchema(attributes, tableNodesDict) {
+    let tablesData = [];
+    _.forEach(tableNodesDict, (node, uid)=>{
+      let [schema, name] = node.getSchemaTableName();
+      tablesData.push({value: uid, label: `(${schema}) ${name}`, image: 'icon-table'});
+    });
+
+    return new ManyToManySchema({
+      left_table_uid: tablesData,
+      left_table_column_attnum: tableNodesDict[attributes.left_table_uid].getColumns().map((col)=>{
         return {
-          value: col.attnum, label: col.name,
+          value: col.attnum, label: col.name, 'image': 'icon-column',
         };
-      });
-    };
-
-    let dialogModel = this.pgBrowser.DataModel.extend({
-      defaults: {
-        left_table_uid: undefined,
-        left_table_column_attnum: undefined,
-        right_table_uid: undefined,
-        right_table_column_attnum: undefined,
+      }),
+      right_table_uid: tablesData,
+      getRefColumns: (uid)=>{
+        return tableNodesDict[uid].getColumns().map((col)=>{
+          return {
+            value: col.attnum, label: col.name, 'image': 'icon-column',
+          };
+        });
       },
-      schema: [{
-        id: 'left_table_uid', label: gettext('Left Table'),
-        type: 'select2', readonly: true,
-        options: ()=>{
-          let retOpts = [];
-          _.forEach(tableNodesDict, (node, uid)=>{
-            let [schema, name] = node.getSchemaTableName();
-            retOpts.push({value: uid, label: `(${schema}) ${name}`});
-          });
-          return retOpts;
-        },
-      }, {
-        id: 'left_table_column_attnum', label: gettext('Left table Column'),
-        type: 'select2', disabled: false, first_empty: false,
-        editable: true, options: (view)=>{
-          return parseColumns(tableNodesDict[view.model.get('left_table_uid')].getColumns());
-        },
-      },{
-        id: 'right_table_uid', label: gettext('Right Table'),
-        type: 'select2', disabled: false,
-        editable: true, options: (view)=>{
-          let retOpts = [];
-          _.forEach(tableNodesDict, (node, uid)=>{
-            if(uid === view.model.get('left_table_uid')) {
-              return;
-            }
-            let [schema, name] = node.getSchemaTableName();
-            retOpts.push({value: uid, label: `(${schema}) ${name}`});
-          });
-          return retOpts;
-        },
-      },{
-        id: 'right_table_column_attnum', label: gettext('Right table Column'),
-        type: 'select2', disabled: false, deps: ['right_table_uid'],
-        editable: true, options: (view)=>{
-          if(view.model.get('right_table_uid')) {
-            return parseColumns(tableNodesDict[view.model.get('right_table_uid')].getColumns());
-          }
-          return [];
-        },
-      }],
-      validate: function(keys) {
-        var msg = undefined;
-
-        // Nothing to validate
-        if (keys && keys.length == 0) {
-          this.errorModel.clear();
-          return null;
-        } else {
-          this.errorModel.clear();
-        }
-
-        if (_.isUndefined(this.get('left_table_column_attnum')) || this.get('left_table_column_attnum') == '') {
-          msg = gettext('Select the left table column.');
-          this.errorModel.set('left_table_column_attnum', msg);
-          return msg;
-        }
-        if (_.isUndefined(this.get('right_table_uid')) || this.get('right_table_uid') == '') {
-          msg = gettext('Select the right table.');
-          this.errorModel.set('right_table_uid', msg);
-          return msg;
-        }
-        if (_.isUndefined(this.get('right_table_column_attnum')) || this.get('right_table_column_attnum') == '') {
-          msg = gettext('Select the right table column.');
-          this.errorModel.set('right_table_column_attnum', msg);
-          return msg;
-        }
-      },
-    });
-
-    return new dialogModel(attributes);
+    }, attributes);
   }
 
   createOrGetDialog(title) {
@@ -122,19 +93,16 @@ export default class ManyToManyDialog {
           `<div class="${dialogName}"></div>`,
           title,
           null,
-          $,
-          this.pgBrowser,
           Alertify,
-          Backform
         );
       });
     }
     return Alertify[dialogName];
   }
 
-  show(title, attributes, tablesData, sVersion, callback) {
+  show(title, attributes, tablesData, serverInfo, callback) {
     let dialogTitle = title || gettext('Unknown');
-    const dialog = this.createOrGetDialog('manytomany_dialog');
-    dialog(dialogTitle, this.getDataModel(attributes, tablesData), callback).resizeTo(this.pgBrowser.stdW.sm, this.pgBrowser.stdH.md);
+    const dialog = this.createOrGetDialog('manytomany_dialog', serverInfo);
+    dialog(dialogTitle, this.getUISchema(attributes, tablesData), callback).resizeTo(this.pgBrowser.stdW.sm, this.pgBrowser.stdH.md);
   }
 }
diff --git a/web/pgadmin/tools/erd/static/js/erd_tool/dialogs/OneToManyDialog.js b/web/pgadmin/tools/erd/static/js/erd_tool/dialogs/OneToManyDialog.js
index efcc5e63b..7cb45810d 100644
--- a/web/pgadmin/tools/erd/static/js/erd_tool/dialogs/OneToManyDialog.js
+++ b/web/pgadmin/tools/erd/static/js/erd_tool/dialogs/OneToManyDialog.js
@@ -8,13 +8,48 @@
 //////////////////////////////////////////////////////////////
 
 import gettext from 'sources/gettext';
-import Backform from 'sources/backform.pgadmin';
 import Alertify from 'pgadmin.alertifyjs';
-import $ from 'jquery';
+import BaseUISchema from 'sources/SchemaView/base_schema.ui';
 
 import DialogWrapper from './DialogWrapper';
 import _ from 'lodash';
 
+class OneToManySchema extends BaseUISchema {
+  constructor(fieldOptions={}, initValues={}) {
+    super({
+      local_table_uid: undefined,
+      local_column_attnum: undefined,
+      referenced_table_uid: undefined,
+      referenced_column_attnum: undefined,
+      ...initValues,
+    });
+    this.fieldOptions = fieldOptions;
+  }
+  get baseFields() {
+    return [{
+      id: 'local_table_uid', label: gettext('Local Table'),
+      type: 'select', readonly: true, controlProps: {allowClear: false},
+      options: this.fieldOptions.local_table_uid,
+    }, {
+      id: 'local_column_attnum', label: gettext('Local Column'),
+      type: 'select', options: this.fieldOptions.local_column_attnum,
+      controlProps: {allowClear: false}, noEmpty: true,
+    },{
+      id: 'referenced_table_uid', label: gettext('Referenced Table'),
+      type: 'select', options: this.fieldOptions.referenced_table_uid,
+      controlProps: {allowClear: false}, noEmpty: true,
+    },{
+      id: 'referenced_column_attnum', label: gettext('Referenced Column'),
+      controlProps: {allowClear: false}, deps: ['referenced_table_uid'], noEmpty: true,
+      type: (state)=>({
+        type: 'select',
+        options: state.referenced_table_uid ? ()=>this.fieldOptions.getRefColumns(state.referenced_table_uid) : [],
+        optionsReloadBasis: state.referenced_table_uid,
+      }),
+    }];
+  }
+}
+
 export default class OneToManyDialog {
   constructor(pgBrowser) {
     this.pgBrowser = pgBrowser;
@@ -24,93 +59,32 @@ export default class OneToManyDialog {
     return 'onetomany_dialog';
   }
 
-  getDataModel(attributes, tableNodesDict) {
-    const parseColumns = (columns)=>{
-      return columns.map((col)=>{
+  getUISchema(attributes, tableNodesDict) {
+    let tablesData = [];
+    _.forEach(tableNodesDict, (node, uid)=>{
+      let [schema, name] = node.getSchemaTableName();
+      tablesData.push({value: uid, label: `(${schema}) ${name}`, image: 'icon-table'});
+    });
+
+    return new OneToManySchema({
+      local_table_uid: tablesData,
+      local_column_attnum: tableNodesDict[attributes.local_table_uid].getColumns().map((col)=>{
         return {
-          value: col.attnum, label: col.name,
+          value: col.attnum, label: col.name, 'image': 'icon-column',
         };
-      });
-    };
-
-    let dialogModel = this.pgBrowser.DataModel.extend({
-      defaults: {
-        local_table_uid: undefined,
-        local_column_attnum: undefined,
-        referenced_table_uid: undefined,
-        referenced_column_attnum: undefined,
+      }),
+      referenced_table_uid: tablesData,
+      getRefColumns: (uid)=>{
+        return tableNodesDict[uid].getColumns().map((col)=>{
+          return {
+            value: col.attnum, label: col.name, 'image': 'icon-column',
+          };
+        });
       },
-      schema: [{
-        id: 'local_table_uid', label: gettext('Local Table'),
-        type: 'select2', readonly: true,
-        options: ()=>{
-          let retOpts = [];
-          _.forEach(tableNodesDict, (node, uid)=>{
-            let [schema, name] = node.getSchemaTableName();
-            retOpts.push({value: uid, label: `(${schema}) ${name}`});
-          });
-          return retOpts;
-        },
-      }, {
-        id: 'local_column_attnum', label: gettext('Local Column'),
-        type: 'select2', disabled: false, first_empty: false,
-        editable: true, options: (view)=>{
-          return parseColumns(tableNodesDict[view.model.get('local_table_uid')].getColumns());
-        },
-      },{
-        id: 'referenced_table_uid', label: gettext('Referenced Table'),
-        type: 'select2', disabled: false,
-        editable: true, options: ()=>{
-          let retOpts = [];
-          _.forEach(tableNodesDict, (node, uid)=>{
-            let [schema, name] = node.getSchemaTableName();
-            retOpts.push({value: uid, label: `(${schema}) ${name}`});
-          });
-          return retOpts;
-        },
-      },{
-        id: 'referenced_column_attnum', label: gettext('Referenced Column'),
-        type: 'select2', disabled: false, deps: ['referenced_table_uid'],
-        editable: true, options: (view)=>{
-          if(view.model.get('referenced_table_uid')) {
-            return parseColumns(tableNodesDict[view.model.get('referenced_table_uid')].getColumns());
-          }
-          return [];
-        },
-      }],
-      validate: function(keys) {
-        var msg = undefined;
-
-        // Nothing to validate
-        if (keys && keys.length == 0) {
-          this.errorModel.clear();
-          return null;
-        } else {
-          this.errorModel.clear();
-        }
-
-        if (_.isUndefined(this.get('local_column_attnum')) || this.get('local_column_attnum') == '') {
-          msg = gettext('Select the local column.');
-          this.errorModel.set('local_column_attnum', msg);
-          return msg;
-        }
-        if (_.isUndefined(this.get('referenced_table_uid')) || this.get('referenced_table_uid') == '') {
-          msg = gettext('Select the referenced table.');
-          this.errorModel.set('referenced_table_uid', msg);
-          return msg;
-        }
-        if (_.isUndefined(this.get('referenced_column_attnum')) || this.get('referenced_column_attnum') == '') {
-          msg = gettext('Select the referenced table column.');
-          this.errorModel.set('referenced_column_attnum', msg);
-          return msg;
-        }
-      },
-    });
-
-    return new dialogModel(attributes);
+    }, attributes);
   }
 
-  createOrGetDialog(title) {
+  createOrGetDialog(title, sVersion) {
     const dialogName = this.dialogName();
 
     if (!Alertify[dialogName]) {
@@ -119,19 +93,17 @@ export default class OneToManyDialog {
           `<div class="${dialogName}"></div>`,
           title,
           null,
-          $,
-          this.pgBrowser,
           Alertify,
-          Backform
+          sVersion
         );
       });
     }
     return Alertify[dialogName];
   }
 
-  show(title, attributes, tablesData, sVersion, callback) {
+  show(title, attributes, tablesData, serverInfo, callback) {
     let dialogTitle = title || gettext('Unknown');
-    const dialog = this.createOrGetDialog('onetomany_dialog');
-    dialog(dialogTitle, this.getDataModel(attributes, tablesData), callback).resizeTo(this.pgBrowser.stdW.sm, this.pgBrowser.stdH.md);
+    const dialog = this.createOrGetDialog('onetomany_dialog', serverInfo);
+    dialog(dialogTitle, this.getUISchema(attributes, tablesData), callback).resizeTo(this.pgBrowser.stdW.sm, this.pgBrowser.stdH.md);
   }
 }
diff --git a/web/pgadmin/tools/erd/static/js/erd_tool/dialogs/TableDialog.js b/web/pgadmin/tools/erd/static/js/erd_tool/dialogs/TableDialog.js
index 3375fdc6f..eafc881e7 100644
--- a/web/pgadmin/tools/erd/static/js/erd_tool/dialogs/TableDialog.js
+++ b/web/pgadmin/tools/erd/static/js/erd_tool/dialogs/TableDialog.js
@@ -8,37 +8,22 @@
 //////////////////////////////////////////////////////////////
 
 import gettext from 'sources/gettext';
-import Backgrid from 'sources/backgrid.pgadmin';
-import Backform from 'sources/backform.pgadmin';
 import Alertify from 'pgadmin.alertifyjs';
-import $ from 'jquery';
 import _ from 'lodash';
+import BaseUISchema from 'sources/SchemaView/base_schema.ui';
 
 import DialogWrapper from './DialogWrapper';
+import TableSchema, { ConstraintsSchema } from '../../../../../../browser/server_groups/servers/databases/schemas/tables/static/js/table.ui';
+import ColumnSchema from '../../../../../../browser/server_groups/servers/databases/schemas/tables/columns/static/js/column.ui';
+import ForeignKeySchema from '../../../../../../browser/server_groups/servers/databases/schemas/tables/constraints/foreign_key/static/js/foreign_key.ui';
 
-export function transformToSupported(data) {
-  /* Table fields */
-  data = _.pick(data, ['oid', 'name', 'schema', 'description', 'columns', 'primary_key', 'foreign_key']);
-
-  /* Columns */
-  data['columns'] = data['columns'].map((column)=>{
-    return _.pick(column,[
-      'name','description','attowner','attnum','cltype','min_val_attlen','min_val_attprecision','max_val_attlen',
-      'max_val_attprecision', 'is_primary_key','attnotnull','attlen','attprecision','attidentity','colconstype',
-      'seqincrement','seqstart','seqmin','seqmax','seqcache','seqcycle',
-    ]);
-  });
-
-  /* Primary key */
-  data['primary_key'] = data['primary_key'].map((primary_key)=>{
-    primary_key = _.pick(primary_key, ['columns']);
-    primary_key['columns'] = primary_key['columns'].map((column)=>{
-      return _.pick(column, ['column']);
-    });
-    return primary_key;
-  });
+class EmptySchema extends BaseUISchema {
+  get baseFields() {
+    return [];
+  }
+  changeColumnOptions() {
 
-  return data;
+  }
 }
 
 export default class TableDialog {
@@ -47,682 +32,81 @@ export default class TableDialog {
   }
 
   dialogName() {
-    return 'entity_dialog';
+    return 'table_dialog';
   }
 
-  getDataModel(attributes, isNew, allTables, colTypes, schemas, sVersion) {
-    let dialogObj = this;
-    let columnsModel = this.pgBrowser.DataModel.extend({
-      idAttribute: 'attnum',
-      defaults: {
-        name: undefined,
-        description: undefined,
-        attowner: undefined,
-        attnum: undefined,
-        cltype: undefined,
-        min_val_attlen: undefined,
-        min_val_attprecision: undefined,
-        max_val_attlen: undefined,
-        max_val_attprecision: undefined,
-        is_primary_key: false,
-        attnotnull: false,
-        attlen: null,
-        attprecision: null,
-        attidentity: 'a',
-        colconstype: 'n',
-        seqincrement: undefined,
-        seqstart: undefined,
-        seqmin: undefined,
-        seqmax: undefined,
-        seqcache: undefined,
-        seqcycle: undefined,
-      },
-      initialize: function(attrs) {
-        if (_.size(attrs) !== 0) {
-          this.set({
-            'old_attidentity': this.get('attidentity'),
-          }, {silent: true});
-        }
-        dialogObj.pgBrowser.DataModel.prototype.initialize.apply(this, arguments);
-
-        if(!this.get('cltype') && colTypes.length > 0) {
-          this.set({
-            'cltype': colTypes[0]['value'],
-          }, {silent: true});
-        }
-      },
-      schema: [{
-        id: 'name', label: gettext('Name'), cell: 'string',
-        type: 'text', disabled: false,
-        cellHeaderClasses: 'width_percent_30',
-        editable: true,
-      }, {
-        // Need to show this field only when creating new table
-        // [in SubNode control]
-        id: 'is_primary_key', label: gettext('Primary key?'),
-        cell: Backgrid.Extension.TableChildSwitchCell, type: 'switch',
-        deps: ['name'], cellHeaderClasses: 'width_percent_5',
-        options: {
-          onText: gettext('Yes'), offText: gettext('No'),
-          onColor: 'success', offColor: 'ternary',
-        },
-        visible: function () {
-          return true;
-        },
-        disabled: false,
-        editable: true,
-      }, {
-        id: 'description', label: gettext('Comment'), cell: 'string', type: 'multiline',
-      }, {
-        id: 'cltype', label: gettext('Data type'),
-        cell: 'select2',
-        type: 'select2', disabled: false,
-        control: 'select2',
-        cellHeaderClasses: 'width_percent_30',
-        select2: { allowClear: false, first_empty: false }, group: gettext('Definition'),
-        options: function () {
-          return colTypes;
-        },
-      }, {
-        id: 'attlen', label: gettext('Length/Precision'), cell: Backgrid.Extension.IntegerDepCell,
-        deps: ['cltype'], type: 'int', group: gettext('Definition'), cellHeaderClasses: 'width_percent_20',
-        disabled: function (m) {
-          var of_type = m.get('cltype'),
-            flag = true;
-          _.each(colTypes, function (o) {
-            if (of_type == o.value) {
-              if (o.length) {
-                m.set('min_val_attlen', o.min_val, { silent: true });
-                m.set('max_val_attlen', o.max_val, { silent: true });
-                flag = false;
-              }
-            }
-          });
-
-          flag && setTimeout(function () {
-            if (m.get('attlen')) {
-              m.set('attlen', null);
-            }
-          }, 10);
-
-          return flag;
-        },
-        editable: function (m) {
-          var of_type = m.get('cltype'),
-            flag = false;
-          _.each(colTypes, function (o) {
-            if (of_type == o.value) {
-              if (o.length) {
-                m.set('min_val_attlen', o.min_val, { silent: true });
-                m.set('max_val_attlen', o.max_val, { silent: true });
-                flag = true;
-              }
-            }
-          });
-
-          !flag && setTimeout(function () {
-            if (m.get('attlen')) {
-              m.set('attlen', null);
-            }
-          }, 10);
-
-          return flag;
-        },
-      }, {
-        id: 'attprecision', label: gettext('Scale'), cell: Backgrid.Extension.IntegerDepCell,
-        deps: ['cltype'], type: 'int', group: gettext('Definition'), cellHeaderClasses: 'width_percent_20',
-        disabled: function (m) {
-          var of_type = m.get('cltype'),
-            flag = true;
-          _.each(colTypes, function (o) {
-            if (of_type == o.value) {
-              if (o.precision) {
-                m.set('min_val_attprecision', 0, { silent: true });
-                m.set('max_val_attprecision', o.max_val, { silent: true });
-                flag = false;
-              }
-            }
-          });
-
-          flag && setTimeout(function () {
-            if (m.get('attprecision')) {
-              m.set('attprecision', null);
-            }
-          }, 10);
-          return flag;
-        },
-        editable: function (m) {
-          if (!colTypes) {
-            // datatypes not loaded yet, may be this call is from CallByNeed from backgrid cell initialize.
-            return true;
-          }
-
-          var of_type = m.get('cltype'),
-            flag = false;
-          _.each(colTypes, function (o) {
-            if (of_type == o.value) {
-              if (o.precision) {
-                m.set('min_val_attprecision', 0, { silent: true });
-                m.set('max_val_attprecision', o.max_val, { silent: true });
-                flag = true;
-              }
-            }
-          });
-
-          !flag && setTimeout(function () {
-            if (m.get('attprecision')) {
-              m.set('attprecision', null);
-            }
-          }, 10);
-
-          return flag;
-        },
-      }, {
-        id: 'attnotnull', label: gettext('Not NULL?'), cell: 'switch',
-        type: 'switch', cellHeaderClasses: 'width_percent_20',
-        group: gettext('Constraints'),
-        options: { onText: gettext('Yes'), offText: gettext('No'), onColor: 'success', offColor: 'ternary' },
-        disabled: function(m) {
-          if (m.get('colconstype') == 'i') {
-            setTimeout(function () {
-              m.set('attnotnull', true);
-            }, 10);
-          }
-          return false;
-        },
-      }, {
-        id: 'colconstype',
-        label: gettext('Type'),
-        cell: 'string',
-        type: 'radioModern',
-        controlsClassName: 'pgadmin-controls col-12 col-sm-9',
-        controlLabelClassName: 'control-label col-sm-3 col-12',
-        group: gettext('Constraints'),
-        options: function() {
-          var opt_array = [
-            {'label': gettext('NONE'), 'value': 'n'},
-            {'label': gettext('IDENTITY'), 'value': 'i'},
-          ];
-
-          if (sVersion >= 120000) {
-            opt_array.push({
-              'label': gettext('GENERATED'),
-              'value': 'g',
-            });
-          }
-
-          return opt_array;
-        },
-        disabled: false,
-        visible: function() {
-          if (sVersion >= 100000) {
-            return true;
-          }
-          return false;
-        },
-      }, {
-        id: 'attidentity', label: gettext('Identity'), control: 'select2',
-        cell: 'select2',
-        select2: {placeholder: 'Select identity', allowClear: false, width: '100%'},
-        group: gettext('Constraints'),
-        'options': [
-          {label: gettext('ALWAYS'), value: 'a'},
-          {label: gettext('BY DEFAULT'), value: 'd'},
-        ],
-        deps: ['colconstype'],
-        visible: function(m) {
-          if (sVersion >= 100000 && m.isTypeIdentity(m)) {
-            return true;
-          }
-          return false;
-        },
-        disabled: function() {
-          return false;
-        },
-      }, {
-        id: 'seqincrement', label: gettext('Increment'), type: 'int',
-        mode: ['properties', 'create', 'edit'], group: gettext('Constraints'),
-        min: 1, deps: ['attidentity', 'colconstype'], disabled: 'isIdentityColumn',
-        visible: 'isTypeIdentity',
-      },{
-        id: 'seqstart', label: gettext('Start'), type: 'int',
-        mode: ['properties', 'create', 'edit'], group: gettext('Constraints'),
-        disabled: function(m) {
-          let isIdentity = m.get('attidentity');
-          if(!_.isUndefined(isIdentity) && !_.isNull(isIdentity) && !_.isEmpty(isIdentity))
-            return false;
-          return true;
-        }, deps: ['attidentity', 'colconstype'],
-        visible: 'isTypeIdentity',
-      },{
-        id: 'seqmin', label: gettext('Minimum'), type: 'int',
-        mode: ['properties', 'create', 'edit'], group: gettext('Constraints'),
-        deps: ['attidentity', 'colconstype'], disabled: 'isIdentityColumn',
-        visible: 'isTypeIdentity',
-      },{
-        id: 'seqmax', label: gettext('Maximum'), type: 'int',
-        mode: ['properties', 'create', 'edit'], group: gettext('Constraints'),
-        deps: ['attidentity', 'colconstype'], disabled: 'isIdentityColumn',
-        visible: 'isTypeIdentity',
-      },{
-        id: 'seqcache', label: gettext('Cache'), type: 'int',
-        mode: ['properties', 'create', 'edit'], group: gettext('Constraints'),
-        min: 1, deps: ['attidentity', 'colconstype'], disabled: 'isIdentityColumn',
-        visible: 'isTypeIdentity',
-      },{
-        id: 'seqcycle', label: gettext('Cycled'), type: 'switch',
-        mode: ['properties', 'create', 'edit'], group: gettext('Constraints'),
-        deps: ['attidentity', 'colconstype'], disabled: 'isIdentityColumn',
-        visible: 'isTypeIdentity',
-      }],
-      validate: function(keys) {
-        var msg = undefined;
-
-        // Nothing to validate
-        if (keys && keys.length == 0) {
-          this.errorModel.clear();
-          return null;
-        } else {
-          this.errorModel.clear();
-        }
-
-        if (_.isUndefined(this.get('name'))
-            || String(this.get('name')).replace(/^\s+|\s+$/g, '') == '') {
-          msg = gettext('Column name cannot be empty.');
-          this.errorModel.set('name', msg);
-          return msg;
-        }
-
-        if (_.isUndefined(this.get('cltype'))
-            || String(this.get('cltype')).replace(/^\s+|\s+$/g, '') == '') {
-          msg = gettext('Column type cannot be empty.');
-          this.errorModel.set('cltype', msg);
-          return msg;
-        }
-
-        if (!_.isUndefined(this.get('cltype'))
-              && !_.isUndefined(this.get('attlen'))
-              && !_.isNull(this.get('attlen'))
-              && this.get('attlen') !== '') {
-          // Validation for Length field
-          if (this.get('attlen') < this.get('min_val_attlen'))
-            msg = gettext('Length/Precision should not be less than: ') + this.get('min_val_attlen');
-          if (this.get('attlen') > this.get('max_val_attlen'))
-            msg = gettext('Length/Precision should not be greater than: ') + this.get('max_val_attlen');
-          // If we have any error set then throw it to user
-          if(msg) {
-            this.errorModel.set('attlen', msg);
-            return msg;
-          }
-        }
-
-        if (!_.isUndefined(this.get('cltype'))
-              && !_.isUndefined(this.get('attprecision'))
-              && !_.isNull(this.get('attprecision'))
-              && this.get('attprecision') !== '') {
-          // Validation for precision field
-          if (this.get('attprecision') < this.get('min_val_attprecision'))
-            msg = gettext('Scale should not be less than: ') + this.get('min_val_attprecision');
-          if (this.get('attprecision') > this.get('max_val_attprecision'))
-            msg = gettext('Scale should not be greater than: ') + this.get('max_val_attprecision');
-          // If we have any error set then throw it to user
-          if(msg) {
-            this.errorModel.set('attprecision', msg);
-            return msg;
-          }
-        }
-
-        var minimum = this.get('seqmin'),
-          maximum = this.get('seqmax'),
-          start = this.get('seqstart');
-
-        if (!this.isNew() && this.get('colconstype') == 'i' &&
-          (this.get('old_attidentity') == 'a' || this.get('old_attidentity') == 'd') &&
-          (this.get('attidentity') == 'a' || this.get('attidentity') == 'd')) {
-          if (_.isUndefined(this.get('seqincrement'))
-            || String(this.get('seqincrement')).replace(/^\s+|\s+$/g, '') == '') {
-            msg = gettext('Increment value cannot be empty.');
-            this.errorModel.set('seqincrement', msg);
-            return msg;
-          } else {
-            this.errorModel.unset('seqincrement');
-          }
-
-          if (_.isUndefined(this.get('seqmin'))
-            || String(this.get('seqmin')).replace(/^\s+|\s+$/g, '') == '') {
-            msg = gettext('Minimum value cannot be empty.');
-            this.errorModel.set('seqmin', msg);
-            return msg;
-          } else {
-            this.errorModel.unset('seqmin');
-          }
-
-          if (_.isUndefined(this.get('seqmax'))
-            || String(this.get('seqmax')).replace(/^\s+|\s+$/g, '') == '') {
-            msg = gettext('Maximum value cannot be empty.');
-            this.errorModel.set('seqmax', msg);
-            return msg;
-          } else {
-            this.errorModel.unset('seqmax');
-          }
-
-          if (_.isUndefined(this.get('seqcache'))
-            || String(this.get('seqcache')).replace(/^\s+|\s+$/g, '') == '') {
-            msg = gettext('Cache value cannot be empty.');
-            this.errorModel.set('seqcache', msg);
-            return msg;
-          } else {
-            this.errorModel.unset('seqcache');
-          }
-        }
-        var min_lt = gettext('Minimum value must be less than maximum value.'),
-          start_lt = gettext('Start value cannot be less than minimum value.'),
-          start_gt = gettext('Start value cannot be greater than maximum value.');
-
-        if (_.isEmpty(minimum) || _.isEmpty(maximum))
-          return null;
-
-        if ((minimum == 0 && maximum == 0) ||
-            (parseInt(minimum, 10) >= parseInt(maximum, 10))) {
-          this.errorModel.set('seqmin', min_lt);
-          return min_lt;
-        } else {
-          this.errorModel.unset('seqmin');
-        }
-
-        if (start && minimum && parseInt(start) < parseInt(minimum)) {
-          this.errorModel.set('seqstart', start_lt);
-          return start_lt;
-        } else {
-          this.errorModel.unset('seqstart');
-        }
-
-        if (start && maximum && parseInt(start) > parseInt(maximum)) {
-          this.errorModel.set('seqstart', start_gt);
-          return start_gt;
-        } else {
-          this.errorModel.unset('seqstart');
-        }
-
-        return null;
-      },
-      // Check whether the column is identity column or not
-      isIdentityColumn: function(m) {
-        let isIdentity = m.get('attidentity');
-        if(!_.isUndefined(isIdentity) && !_.isNull(isIdentity) && !_.isEmpty(isIdentity))
-          return false;
-        return true;
-      },
-      // Check whether the column is a identity column
-      isTypeIdentity: function(m) {
-        let colconstype = m.get('colconstype');
-        if (!_.isUndefined(colconstype) && !_.isNull(colconstype) && colconstype == 'i') {
-          return true;
-        }
-        return false;
-      },
-      // Check whether the column is a generated column
-      isTypeGenerated: function(m) {
-        let colconstype = m.get('colconstype');
-        if (!_.isUndefined(colconstype) && !_.isNull(colconstype) && colconstype == 'g') {
-          return true;
-        }
-        return false;
-      },
-    });
-
-    const formatSchemaItem = function(opt) {
-      if (!opt.id) {
-        return opt.text;
-      }
-
-      var optimage = $(opt.element).data('image');
-
-      if (!optimage) {
-        return opt.text;
-      } else {
-        return $('<span></span>').append(
-          $('<span></span>', {
-            class: 'wcTabIcon ' + optimage,
-          })
-        ).append($('<span></span>').text(opt.text));
-      }
-    };
-
-    let dialogModel = this.pgBrowser.DataModel.extend({
-      defaults: {
-        name: undefined,
-        schema: undefined,
-        description: undefined,
-        columns: [],
-        primary_key: [],
-      },
-      initialize: function() {
-        dialogObj.pgBrowser.DataModel.prototype.initialize.apply(this, arguments);
-
-        if(!this.get('schema') && schemas.length > 0) {
-          this.set({
-            'schema': schemas[0]['name'],
-          }, {silent: true});
-        }
+  getUISchema(attributes, isNew, tableNodesDict, colTypes, schemas) {
+    let treeNodeInfo = undefined;
+
+    let columnSchema = new ColumnSchema(
+      ()=>{},
+      treeNodeInfo,
+      ()=>colTypes,
+      ()=>[],
+      ()=>[],
+      true,
+    );
+
+    return new TableSchema(
+      {
+        relowner: [],
+        schema: schemas.map((schema)=>{
+          return {
+            'value': schema['name'],
+            'image': 'icon-schema',
+            'label': schema['name'],
+          };
+        }),
+        spcname: [],
+        coll_inherits: [],
+        typname: [],
+        like_relation: [],
       },
-      schema: [{
-        id: 'name', label: gettext('Name'), type: 'text', disabled: false,
-      },{
-        id: 'schema', label: gettext('Schema'), type: 'text',
-        control: 'select2', select2: {
-          allowClear: false, first_empty: false,
-          templateResult: formatSchemaItem,
-          templateSelection: formatSchemaItem,
-        },
-        options: function () {
-          return schemas.map((schema)=>{
-            return {
-              'value': schema['name'],
-              'image': 'icon-schema',
-              'label': schema['name'],
-            };
-          });
-        },
-        filter: function(d) {
-          // If schema name start with pg_* then we need to exclude them
-          if(d && d.label.match(/^pg_/))
-          {
-            return false;
-          }
-          return true;
-        },
-      },{
-        id: 'description', label: gettext('Comment'), type: 'multiline',
-      },{
-        id: 'columns', label: gettext('Columns'), type: 'collection', mode: ['create'],
-        group: gettext('Columns'),
-        model: columnsModel,
-        subnode: columnsModel,
-        disabled: false,
-        uniqueCol : ['name'],
-        columns : ['name' , 'cltype', 'attlen', 'attprecision', 'attnotnull', 'is_primary_key'],
-        control: Backform.UniqueColCollectionControl.extend({
-          initialize: function() {
-
-            Backform.UniqueColCollectionControl.prototype.initialize.apply(this, arguments);
-            var self = this,
-              collection = self.model.get(self.field.get('name'));
-
-            if(collection.isEmpty()) {
-              self.last_attnum = -1;
-            } else {
-              var lastCol = collection.max(function(col) {
-                return col.get('attnum');
+      treeNodeInfo,
+      {
+        columns: ()=>columnSchema,
+        vacuum_settings: ()=>new EmptySchema(),
+        constraints: ()=>new ConstraintsSchema(
+          treeNodeInfo,
+          ()=>new ForeignKeySchema({
+            local_column: [],
+            references: ()=>{
+              let retOpts = [];
+              _.forEach(tableNodesDict, (node, uid)=>{
+                let [schema, name] = node.getSchemaTableName();
+                retOpts.push({value: uid, label: `(${schema}) ${name}`});
               });
-              self.last_attnum = lastCol.get('attnum');
+              return retOpts;
             }
-
-            collection.on('change:is_primary_key', function(m) {
-              var primary_key_coll = self.model.get('primary_key'),
-                column_name = m.get('name'),
-                primary_key, primary_key_column_coll;
-
-              if(m.get('is_primary_key')) {
-                // Add column to primary key.
-                if (primary_key_coll.length < 1) {
-                  primary_key = new (primary_key_coll.model)({}, {
-                    top: self.model,
-                    collection: primary_key_coll,
-                    handler: primary_key_coll,
-                  });
-                  primary_key_coll.add(primary_key);
-                } else {
-                  primary_key = primary_key_coll.first();
-                }
-
-                primary_key_column_coll = primary_key.get('columns');
-                var primary_key_column_exist = primary_key_column_coll.where({column:column_name});
-
-                if (primary_key_column_exist.length == 0) {
-                  var primary_key_column = new (
-                    primary_key_column_coll.model
-                  )({column: column_name}, {
-                    silent: true,
-                    top: self.model,
-                    collection: primary_key_coll,
-                    handler: primary_key_coll,
-                  });
-
-                  primary_key_column_coll.add(primary_key_column);
-                }
-
-                primary_key_column_coll.trigger(
-                  'pgadmin:multicolumn:updated', primary_key_column_coll
-                );
-              } else {
-                // remove column from primary key.
-                if (primary_key_coll.length > 0) {
-                  primary_key = primary_key_coll.first();
-                  // Do not alter existing primary key columns.
-                  if (!_.isUndefined(primary_key.get('oid'))) {
-                    return;
-                  }
-
-                  primary_key_column_coll = primary_key.get('columns');
-                  var removedCols = primary_key_column_coll.where({column:column_name});
-                  if (removedCols.length > 0) {
-                    primary_key_column_coll.remove(removedCols);
-                    _.each(removedCols, function(local_model) {
-                      local_model.destroy();
-                    });
-                    if (primary_key_column_coll.length == 0) {
-                      /* Ideally above line of code should be "primary_key_coll.reset()".
-                       * But our custom DataCollection (extended from Backbone collection in datamodel.js)
-                       * does not respond to reset event, it only supports add, remove, change events.
-                       * And hence no custom event listeners/validators get called for reset event.
-                       */
-                      primary_key_coll.remove(primary_key_coll.first());
-                    }
-                  }
-                  primary_key_column_coll.trigger('pgadmin:multicolumn:updated', primary_key_column_coll);
-                }
-              }
-            });
-
-            collection.on('change:name', function(m) {
-              let primary_key = self.model.get('primary_key').first();
-              if(primary_key) {
-                let updatedCols = primary_key.get('columns').where(
-                  {column: m.previous('name')}
-                );
-                if (updatedCols.length > 0) {
-                  /*
-                  * Table column name has changed so update
-                  * column name in primary key as well.
-                  */
-                  updatedCols[0].set(
-                    {'column': m.get('name')},
-                    {silent: true});
-                }
-              }
-            });
-
-            collection.on('remove', function(m) {
-              let primary_key = self.model.get('primary_key').first();
-              if(primary_key) {
-                let removedCols = primary_key.get('columns').where(
-                  {column: m.get('name')}
-                );
-
-                primary_key.get('columns').remove(removedCols);
-              }
-            });
           },
-        }),
-        canAdd: true,
-        canEdit: true, canDelete: true,
-        // For each row edit/delete button enable/disable
-        canEditRow: true,
-        canDeleteRow: true,
-        allowMultipleEmptyRow: false,
-        beforeAdd: function(newModel) {
-          this.last_attnum++;
-          newModel.set('attnum', this.last_attnum);
-          return newModel;
-        },
-      },{
-        // Here we will create tab control for constraints
-        // We will hide the tab for ERD
-        type: 'nested', control: 'tab', group: gettext('Constraints'), mode: ['properties'],
-        schema: [{
-          id: 'primary_key', label: '',
-          model: this.pgBrowser.Nodes['primary_key'].model.extend({
-            validate: ()=>{},
-          }),
-          subnode: this.pgBrowser.Nodes['primary_key'].model.extend({
-            validate: ()=>{},
-          }),
-          editable: false, type: 'collection',
-        },
-        ],
-      }],
-      validate: function() {
-        var msg,
-          name = this.get('name'),
-          schema = this.get('schema');
-
-        if (
-          _.isUndefined(name) || _.isNull(name) ||
-            String(name).replace(/^\s+|\s+$/g, '') == ''
-        ) {
-          msg = gettext('Table name cannot be empty.');
-          this.errorModel.set('name', msg);
-          return msg;
-        }
-
-        /* Check existing table names */
-        let sameNameCount = _.filter(allTables, (table)=>table[0]==schema&&table[1]==name).length;
-        if(isNew && this.sessAttrs['name'] && sameNameCount > 0 || isNew && sameNameCount > 0) {
-          msg = gettext('Table name already exists.');
-          this.errorModel.set('name', msg);
-          return msg;
-        }
-        this.errorModel.unset('name');
-        if (
-          _.isUndefined(schema) || _.isNull(schema) ||
-            String(schema).replace(/^\s+|\s+$/g, '') == ''
-        ) {
-          msg = gettext('Table schema cannot be empty.');
-          this.errorModel.set('schema', msg);
-          return msg;
-        }
-        this.errorModel.unset('schema');
-
-
-        return null;
+          treeNodeInfo,
+          (params)=>{
+            if(params.tid) {
+              return tableNodesDict[params.tid].getColumns().map((col)=>{
+                return {
+                  value: col.name, label: col.name, 'image': 'icon-column',
+                };
+              });
+            }
+          }, {autoindex: false}, true),
+          ()=>new EmptySchema(),
+          {spcname: []},
+          true
+        ),
       },
-    });
-
-    return new dialogModel(attributes);
+      ()=>new EmptySchema(),
+      ()=>[],
+      ()=>[],
+      ()=>[],
+      ()=>[],
+      isNew ? {
+        schema: schemas[0]?.name,
+      } : attributes,
+      true
+    );
   }
 
-  createOrGetDialog(type) {
+  createOrGetDialog(type, sVersion) {
     const dialogName = this.dialogName();
 
     if (!Alertify[dialogName]) {
@@ -731,19 +115,17 @@ export default class TableDialog {
           `<div class="${dialogName}"></div>`,
           null,
           type,
-          $,
-          this.pgBrowser,
           Alertify,
-          Backform
+          sVersion
         );
       });
     }
     return Alertify[dialogName];
   }
 
-  show(title, attributes, isNew, allTables, colTypes, schemas, sVersion, callback) {
+  show(title, attributes, isNew, tableNodesDict, colTypes, schemas, serverInfo, callback) {
     let dialogTitle = title || gettext('Unknown');
-    const dialog = this.createOrGetDialog('table_dialog');
-    dialog(dialogTitle, this.getDataModel(attributes, isNew, allTables, colTypes, schemas, sVersion), callback).resizeTo(this.pgBrowser.stdW.md, this.pgBrowser.stdH.md);
+    const dialog = this.createOrGetDialog('table_dialog', serverInfo);
+    dialog(dialogTitle, this.getUISchema(attributes, isNew, tableNodesDict, colTypes, schemas, serverInfo), callback).resizeTo(this.pgBrowser.stdW.lg, this.pgBrowser.stdH.md);
   }
 }
diff --git a/web/pgadmin/tools/erd/static/js/erd_tool/dialogs/index.js b/web/pgadmin/tools/erd/static/js/erd_tool/dialogs/index.js
index d58d3f9a6..359085cd2 100644
--- a/web/pgadmin/tools/erd/static/js/erd_tool/dialogs/index.js
+++ b/web/pgadmin/tools/erd/static/js/erd_tool/dialogs/index.js
@@ -7,7 +7,7 @@
 //
 //////////////////////////////////////////////////////////////
 
-import TableDialog, {transformToSupported as transformToSupportedTable} from './TableDialog';
+import TableDialog from './TableDialog';
 import OneToManyDialog from './OneToManyDialog';
 import ManyToManyDialog from './ManyToManyDialog';
 import pgBrowser from 'top/browser/static/js/browser';
@@ -15,7 +15,7 @@ import 'sources/backgrid.pgadmin';
 import 'sources/backform.pgadmin';
 
 export default function getDialog(dialogName) {
-  if(dialogName === 'entity_dialog') {
+  if(dialogName === 'table_dialog') {
     return new TableDialog(pgBrowser);
   } else if(dialogName === 'onetomany_dialog') {
     return new OneToManyDialog(pgBrowser);
@@ -23,10 +23,3 @@ export default function getDialog(dialogName) {
     return new ManyToManyDialog(pgBrowser);
   }
 }
-
-export function transformToSupported(type, data) {
-  if(type == 'table') {
-    return transformToSupportedTable(data);
-  }
-  return data;
-}
diff --git a/web/pgadmin/tools/erd/static/js/erd_tool/index.js b/web/pgadmin/tools/erd/static/js/erd_tool/index.js
index e865c29bd..2b1906f14 100644
--- a/web/pgadmin/tools/erd/static/js/erd_tool/index.js
+++ b/web/pgadmin/tools/erd/static/js/erd_tool/index.js
@@ -12,7 +12,7 @@ import ReactDOM from 'react-dom';
 import _ from 'lodash';
 
 import BodyWidget from './ui_components/BodyWidget';
-import getDialog, {transformToSupported} from './dialogs';
+import getDialog from './dialogs';
 import Alertify from 'pgadmin.alertifyjs';
 import pgWindow from 'sources/window';
 import pgAdmin from 'sources/pgadmin';
@@ -40,7 +40,6 @@ export default class ERDTool {
       <BodyWidget
         params={this.params}
         getDialog={getDialog}
-        transformToSupported={transformToSupported}
         pgWindow={pgWindow}
         pgAdmin={pgAdmin}
         panel={panel}
diff --git a/web/pgadmin/tools/erd/static/js/erd_tool/nodes/TableNode.jsx b/web/pgadmin/tools/erd/static/js/erd_tool/nodes/TableNode.jsx
index c4c62b4b4..db2ff3050 100644
--- a/web/pgadmin/tools/erd/static/js/erd_tool/nodes/TableNode.jsx
+++ b/web/pgadmin/tools/erd/static/js/erd_tool/nodes/TableNode.jsx
@@ -188,7 +188,7 @@ export class TableNodeWidget extends React.Component {
   render() {
     let node_data = this.props.node.getData();
     return (
-      <div className={'table-node ' + (this.props.node.isSelected() ? 'selected': '') } onDoubleClick={()=>{this.props.node.fireEvent({}, 'editNode');}}>
+      <div className={'table-node ' + (this.props.node.isSelected() ? 'selected': '') } onDoubleClick={()=>{this.props.node.fireEvent({}, 'editTable');}}>
         <div className="table-toolbar">
           <DetailsToggleButton className='btn-xs' showDetails={this.state.show_details} onClick={this.toggleShowDetails} onDoubleClick={(e)=>{e.stopPropagation();}} />
           {this.props.node.getNote() &&
diff --git a/web/pgadmin/tools/erd/static/js/erd_tool/ui_components/BodyWidget.jsx b/web/pgadmin/tools/erd/static/js/erd_tool/ui_components/BodyWidget.jsx
index 0e69c0b9a..4ff8825c1 100644
--- a/web/pgadmin/tools/erd/static/js/erd_tool/ui_components/BodyWidget.jsx
+++ b/web/pgadmin/tools/erd/static/js/erd_tool/ui_components/BodyWidget.jsx
@@ -25,6 +25,7 @@ import gettext from 'sources/gettext';
 import url_for from 'sources/url_for';
 import {showERDSqlTool} from 'tools/datagrid/static/js/show_query_tool';
 import 'wcdocker';
+import Theme from '../../../../../../static/js/Theme';
 
 /* Custom react-diagram action for keyboard events */
 export class KeyboardShortcutAction extends Action {
@@ -76,6 +77,9 @@ export default class BodyWidget extends React.Component {
       show_details: true,
       is_new_tab: false,
       preferences: {},
+      table_dialog_open: true,
+      oto_dialog_open: true,
+      otm_dialog_open: true,
     };
     this.diagram = new ERDCore();
     /* Flag for checking if user has opted for save before close */
@@ -88,7 +92,7 @@ export default class BodyWidget extends React.Component {
     this.keyboardActionObj = null;
 
     _.bindAll(this, ['onLoadDiagram', 'onSaveDiagram', 'onSaveAsDiagram', 'onSQLClick',
-      'onImageClick', 'onAddNewNode', 'onEditNode', 'onCloneNode', 'onDeleteNode', 'onNoteClick',
+      'onImageClick', 'onAddNewNode', 'onEditTable', 'onCloneNode', 'onDeleteNode', 'onNoteClick',
       'onNoteClose', 'onOneToManyClick', 'onManyToManyClick', 'onAutoDistribute', 'onDetailsToggle',
       'onDetailsToggle', 'onHelpClick'
     ]);
@@ -130,8 +134,8 @@ export default class BodyWidget extends React.Component {
       'showNote': (event)=>{
         this.showNote(event.node);
       },
-      'editNode': (event) => {
-        this.addEditNode(event.node);
+      'editTable': (event) => {
+        this.addEditTable(event.node);
       },
     };
     Object.keys(diagramEvents).forEach(eventName => {
@@ -150,7 +154,7 @@ export default class BodyWidget extends React.Component {
       [this.state.preferences.generate_sql, this.onSQLClick],
       [this.state.preferences.download_image, this.onImageClick],
       [this.state.preferences.add_table, this.onAddNewNode],
-      [this.state.preferences.edit_table, this.onEditNode],
+      [this.state.preferences.edit_table, this.onEditTable],
       [this.state.preferences.clone_table, this.onCloneNode],
       [this.state.preferences.drop_table, this.onDeleteNode],
       [this.state.preferences.add_edit_note, this.onNoteClick],
@@ -297,19 +301,20 @@ export default class BodyWidget extends React.Component {
   }
 
   getDialog(dialogName) {
-    if(dialogName === 'entity_dialog') {
-      let allTables = this.diagram.getModel().getNodes().map((node)=>{
-        return node.getSchemaTableName();
-      });
+    let serverInfo = {
+      type: this.props.params.server_type,
+      version: this.state.server_version,
+    };
+    if(dialogName === 'table_dialog') {
       return (title, attributes, isNew, callback)=>{
         this.props.getDialog(dialogName).show(
-          title, attributes, isNew, allTables, this.diagram.getCache('colTypes'), this.diagram.getCache('schemas'), this.state.server_version, callback
+          title, attributes, isNew, this.diagram.getModel().getNodesDict(), this.diagram.getCache('colTypes'), this.diagram.getCache('schemas'), serverInfo, callback
         );
       };
     } else if(dialogName === 'onetomany_dialog' || dialogName === 'manytomany_dialog') {
       return (title, attributes, callback)=>{
         this.props.getDialog(dialogName).show(
-          title, attributes, this.diagram.getModel().getNodesDict(), this.state.server_version, callback
+          title, attributes, this.diagram.getModel().getNodesDict(), serverInfo, callback
         );
       };
     }
@@ -328,17 +333,20 @@ export default class BodyWidget extends React.Component {
     }
   }
 
-  addEditNode(node) {
-    let dialog = this.getDialog('entity_dialog');
+  addEditTable(node) {
+    let dialog = this.getDialog('table_dialog');
     if(node) {
       let [schema, table] = node.getSchemaTableName();
       dialog(gettext('Table: %s (%s)', _.escape(table),_.escape(schema)), node.getData(), false, (newData)=>{
+        let oldData = node.getData();
         node.setData(newData);
+        this.diagram.syncTableLinks(node, oldData);
         this.diagram.repaint();
       });
     } else {
-      dialog(gettext('New table'), {name: this.diagram.getNextTableName()}, true, (newData)=>{
+      dialog(gettext('New table'), {}, true, (newData)=>{
         let newNode = this.diagram.addNode(newData);
+        this.diagram.syncTableLinks(newNode);
         newNode.setSelected(true);
       });
     }
@@ -353,15 +361,15 @@ export default class BodyWidget extends React.Component {
     }
   }
 
-  onEditNode() {
+  onEditTable() {
     const selected = this.diagram.getSelectedNodes();
     if(selected.length == 1) {
-      this.addEditNode(selected[0]);
+      this.addEditTable(selected[0]);
     }
   }
 
   onAddNewNode() {
-    this.addEditNode();
+    this.addEditTable();
   }
 
   onCloneNode() {
@@ -385,10 +393,7 @@ export default class BodyWidget extends React.Component {
           node.remove();
         });
         this.diagram.getSelectedLinks().forEach((link)=>{
-          link.getTargetPort().remove();
-          link.getSourcePort().remove();
-          link.setSelected(false);
-          link.remove();
+          this.diagram.removeOneToManyLink(link);
         });
         this.diagram.repaint();
       },
@@ -656,10 +661,7 @@ export default class BodyWidget extends React.Component {
     let dialog = this.getDialog('onetomany_dialog');
     let initData = {local_table_uid: this.diagram.getSelectedNodes()[0].getID()};
     dialog(gettext('One to many relation'), initData, (newData)=>{
-      let newLink = this.diagram.addLink(newData, 'onetomany');
-      this.diagram.clearSelection();
-      newLink.setSelected(true);
-      this.diagram.repaint();
+      this.diagram.addOneToManyLink(newData);
     });
   }
 
@@ -667,46 +669,7 @@ export default class BodyWidget extends React.Component {
     let dialog = this.getDialog('manytomany_dialog');
     let initData = {left_table_uid: this.diagram.getSelectedNodes()[0].getID()};
     dialog(gettext('Many to many relation'), initData, (newData)=>{
-      let nodes = this.diagram.getModel().getNodesDict();
-      let left_table = nodes[newData.left_table_uid];
-      let right_table = nodes[newData.right_table_uid];
-      let tableData = {
-        name: `${left_table.getData().name}_${right_table.getData().name}`,
-        schema: left_table.getData().schema,
-        columns: [{
-          ...left_table.getColumnAt(newData.left_table_column_attnum),
-          'name': `${left_table.getData().name}_${left_table.getColumnAt(newData.left_table_column_attnum).name}`,
-          'is_primary_key': false,
-          'attnum': 0,
-        },{
-          ...right_table.getColumnAt(newData.right_table_column_attnum),
-          'name': `${right_table.getData().name}_${right_table.getColumnAt(newData.right_table_column_attnum).name}`,
-          'is_primary_key': false,
-          'attnum': 1,
-        }],
-      };
-      let newNode = this.diagram.addNode(tableData);
-      this.diagram.clearSelection();
-      newNode.setSelected(true);
-
-      let linkData = {
-        local_table_uid: newNode.getID(),
-        local_column_attnum: newNode.getColumns()[0].attnum,
-        referenced_table_uid: newData.left_table_uid,
-        referenced_column_attnum : newData.left_table_column_attnum,
-      };
-      this.diagram.addLink(linkData, 'onetomany');
-
-      linkData = {
-        local_table_uid: newNode.getID(),
-        local_column_attnum: newNode.getColumns()[1].attnum,
-        referenced_table_uid: newData.right_table_uid,
-        referenced_column_attnum : newData.right_table_column_attnum,
-      };
-
-      this.diagram.addLink(linkData, 'onetomany');
-
-      this.diagram.repaint();
+      this.diagram.addManyToManyLink(newData);
     });
   }
 
@@ -794,10 +757,7 @@ export default class BodyWidget extends React.Component {
 
     try {
       let response = await axios.get(url);
-      let tables = response.data.data.map((table)=>{
-        return this.props.transformToSupported('table', table);
-      });
-      this.diagram.deserializeData(tables);
+      this.diagram.deserializeData(response.data.data);
       return true;
     } catch (error) {
       this.handleAxiosCatch(error);
@@ -809,7 +769,7 @@ export default class BodyWidget extends React.Component {
 
   render() {
     return (
-      <>
+      <Theme>
         <ToolBar id="btn-toolbar">
           <ButtonGroup>
             <IconButton id="open-file" icon="fa fa-folder-open" onClick={this.onLoadDiagram} title={gettext('Load from file')}
@@ -828,7 +788,7 @@ export default class BodyWidget extends React.Component {
           <ButtonGroup>
             <IconButton id="add-node" icon="fa fa-plus-square" onClick={this.onAddNewNode} title={gettext('Add table')}
               shortcut={this.state.preferences.add_table}/>
-            <IconButton id="edit-node" icon="fa fa-pencil-alt" onClick={this.onEditNode} title={gettext('Edit table')}
+            <IconButton id="edit-node" icon="fa fa-pencil-alt" onClick={this.onEditTable} title={gettext('Edit table')}
               shortcut={this.state.preferences.edit_table} disabled={!this.state.single_node_selected || this.state.single_link_selected}/>
             <IconButton id="clone-node" icon="fa fa-clone" onClick={this.onCloneNode} title={gettext('Clone table')}
               shortcut={this.state.preferences.clone_table} disabled={!this.state.single_node_selected || this.state.single_link_selected}/>
@@ -869,7 +829,7 @@ export default class BodyWidget extends React.Component {
           <Loader message={this.state.loading_msg} autoEllipsis={true}/>
           <CanvasWidget className="diagram-canvas flex-grow-1" ref={(ele)=>{this.canvasEle = ele?.ref?.current;}} engine={this.diagram.getEngine()} />
         </div>
-      </>
+      </Theme>
     );
   }
 }
@@ -888,7 +848,6 @@ BodyWidget.propTypes = {
     gen: PropTypes.bool.isRequired,
   }),
   getDialog: PropTypes.func.isRequired,
-  transformToSupported: PropTypes.func.isRequired,
   pgWindow: PropTypes.object.isRequired,
   pgAdmin: PropTypes.object.isRequired,
   alertify: PropTypes.object.isRequired,
diff --git a/web/pgadmin/tools/erd/static/scss/_erd.scss b/web/pgadmin/tools/erd/static/scss/_erd.scss
index f48d65b4c..150ef6778 100644
--- a/web/pgadmin/tools/erd/static/scss/_erd.scss
+++ b/web/pgadmin/tools/erd/static/scss/_erd.scss
@@ -205,3 +205,14 @@
     }
   }
 }
+
+.alertify {
+  .erd-dialog {
+    .ajs-body .ajs-content {
+      bottom: 0!important;
+    }
+    .ajs-footer {
+      display: none;
+    }
+  }
+}
diff --git a/web/regression/javascript/erd/erd_core_spec.js b/web/regression/javascript/erd/erd_core_spec.js
index b26a5fc05..635d488d4 100644
--- a/web/regression/javascript/erd/erd_core_spec.js
+++ b/web/regression/javascript/erd/erd_core_spec.js
@@ -9,6 +9,7 @@
 import ERDCore from 'pgadmin.tools.erd/erd_tool/ERDCore';
 import * as createEngineLib from '@projectstorm/react-diagrams';
 import TEST_TABLES_DATA from './test_tables';
+import { FakeLink, FakeNode } from './fake_item';
 
 describe('ERDCore', ()=>{
   let eleFactory = jasmine.createSpyObj('nodeFactories', {
@@ -132,7 +133,8 @@ describe('ERDCore', ()=>{
     });
 
     it('addNode', ()=>{
-      let newNode = jasmine.createSpyObj('newNode', ['setPosition']);
+      let newNode = new FakeNode({});
+      spyOn(newNode, 'setPosition');
       spyOn(erdCoreObj, 'getNewNode').and.returnValue(newNode);
       spyOn(erdCoreObj, 'clearSelection');
 
@@ -151,33 +153,17 @@ describe('ERDCore', ()=>{
 
 
     it('addLink', ()=>{
+      let node1 = new FakeNode({'name': 'table1'}, 'id1');
+      let node2 = new FakeNode({'name': 'table2'}, 'id2');
+      spyOn(node1, 'addPort').and.callThrough();
+      spyOn(node2, 'addPort').and.callThrough();
       let nodesDict = {
-        'id1': {
-          serializeData: function(){ return {
-            'name': 'table1',
-          };},
-          getPortName: function(attnum) {
-            return `port-${attnum}`;
-          },
-          getPort: function() {
-            return null;
-          },
-          addPort: jasmine.createSpy('addPort').and.callFake((obj)=>obj),
-        },
-        'id2': {
-          serializeData: function(){ return {
-            'name': 'table2',
-          };},
-          getPortName: function(attnum) {
-            return `port-${attnum}`;
-          },
-          getPort: function() {
-            return null;
-          },
-          addPort: jasmine.createSpy('addPort').and.callFake((obj)=>obj),
-        },
+        'id1': node1,
+        'id2': node2,
       };
-      let link = jasmine.createSpyObj('link', ['setSourcePort', 'setTargetPort']);
+      let link = new FakeLink();
+      spyOn(link, 'setSourcePort').and.callThrough();
+      spyOn(link, 'setTargetPort').and.callThrough();
       spyOn(erdEngine.getModel(), 'getNodesDict').and.returnValue(nodesDict);
       spyOn(erdCoreObj, 'getNewLink').and.callFake(function() {
         return link;
@@ -199,7 +185,6 @@ describe('ERDCore', ()=>{
       expect(nodesDict['id2'].addPort).toHaveBeenCalledWith({name: 'port-3'});
       expect(link.setSourcePort).toHaveBeenCalledWith({name: 'port-1'});
       expect(link.setTargetPort).toHaveBeenCalledWith({name: 'port-3'});
-
     });
 
     it('serialize', ()=>{
@@ -222,41 +207,26 @@ describe('ERDCore', ()=>{
     });
 
     it('serializeData', ()=>{
-      spyOn(erdEngine.getModel(), 'getNodesDict').and.returnValue({
-        'id1': {
-          serializeData: function(){ return {
-            'name': 'table1',
-          };},
-        },
-        'id2': {
-          serializeData: function(){ return {
-            'name': 'table2',
-          };},
-        },
-      });
+      let node1 = new FakeNode({'name': 'table1'}, 'id1');
+      let node2 = new FakeNode({'name': 'table2'}, 'id2');
+      let nodesDict = {
+        'id1': node1,
+        'id2': node2,
+      };
+      spyOn(erdEngine.getModel(), 'getNodesDict').and.returnValue(nodesDict);
       spyOn(erdEngine.getModel(), 'getLinks').and.returnValue([
-        {
-          serializeData:  function(){ return {
-            'name': 'link1',
-          };},
-          getID:  function(){ return 'lid1'; },
-        },
-        {
-          serializeData:  function(){ return {
-            'name': 'link2',
-          };},
-          getID:  function(){ return 'lid2'; },
-        },
+        new FakeLink({
+          'name': 'link1',
+        }, 'lid1'),
+        new FakeLink({
+          'name': 'link2',
+        }, 'lid2'),
       ]);
       expect(JSON.stringify(erdCoreObj.serializeData())).toEqual(JSON.stringify({
         nodes: {
           'id1': {'name': 'table1'},
           'id2': {'name': 'table2'},
         },
-        links: {
-          'lid1': {'name': 'link1'},
-          'lid2': {'name': 'link2'},
-        },
       }));
     });
 
@@ -276,6 +246,9 @@ describe('ERDCore', ()=>{
           addPort: function() {
 
           },
+          getData: function() {
+            return table;
+          }
         };
       });
       spyOn(erdEngine.getModel(), 'getNodesDict').and.returnValue(nodesDict);
@@ -288,11 +261,7 @@ describe('ERDCore', ()=>{
       });
       spyOn(erdCoreObj, 'getNewPort').and.returnValue({id: 'id'});
       spyOn(erdCoreObj, 'addNode').and.callFake(function(data) {
-        return {
-          getID: function() {
-            return `id-${data.name}`;
-          },
-        };
+        return new FakeNode({}, `id-${data.name}`);
       });
       spyOn(erdCoreObj, 'addLink');
       spyOn(erdCoreObj, 'dagreDistributeNodes');
@@ -319,8 +288,8 @@ describe('ERDCore', ()=>{
 
     it('getNodesData', ()=>{
       spyOn(erdEngine.getModel(), 'getNodes').and.returnValue([
-        {getData: function () {return {name:'node1'};}},
-        {getData: function () {return {name:'node2'};}},
+        new FakeNode({name:'node1'}),
+        new FakeNode({name:'node2'}),
       ]);
       expect(JSON.stringify(erdCoreObj.getNodesData())).toEqual(JSON.stringify([
         {name:'node1'}, {name:'node2'},
diff --git a/web/regression/javascript/erd/fake_item.js b/web/regression/javascript/erd/fake_item.js
new file mode 100644
index 000000000..498ef1db1
--- /dev/null
+++ b/web/regression/javascript/erd/fake_item.js
@@ -0,0 +1,42 @@
+import _ from 'lodash';
+
+export class FakeNode {
+  constructor(data, id='nid1') {
+    this.data = data || {};
+    this.id = id;
+  }
+  setSelected() {}
+  getColumns() {return this.data.columns;}
+  getID() {return this.id;}
+  setData(data) {this.data = data;}
+  getData() {return this.data;}
+  getPosition() {return {x: 30, y: 30};}
+  setPosition() {}
+  serializeData() {return this.getData();}
+  getPortName(attnum) {return `port-${attnum}`;}
+  getPort() {return null;}
+  addPort(obj) {return obj;}
+  getColumnAt(pos) {return _.find(this.getColumns()||[], (c)=>c.attnum==pos);}
+  remove() {}
+  getSchemaTableName() {return [this.data.schema, this.data.name];}
+  cloneData(tabName) {
+    let retVal = {...this.data};
+    retVal.name = tabName;
+    return retVal;
+  }
+}
+
+export class FakeLink {
+  constructor(data, id='lid1') {
+    this.data = data;
+    this.id = id;
+  }
+  setSelected() {}
+  getID() {return this.id;}
+  getData() {return this.data;}
+  getSourcePort() {return {remove: ()=>{}};}
+  setSourcePort() {}
+  getTargetPort() {return {remove: ()=>{}};}
+  setTargetPort() {}
+  remove() {}
+}
diff --git a/web/regression/javascript/erd/ui_components/body_widget_spec.js b/web/regression/javascript/erd/ui_components/body_widget_spec.js
index 2095ecd90..ca30f63ff 100644
--- a/web/regression/javascript/erd/ui_components/body_widget_spec.js
+++ b/web/regression/javascript/erd/ui_components/body_widget_spec.js
@@ -10,6 +10,7 @@ import * as erdModule from 'pgadmin.tools.erd/erd_module';
 import erdPref from './erd_preferences';
 import BodyWidget from 'pgadmin.tools.erd/erd_tool/ui_components/BodyWidget';
 import * as ERDSqlTool from 'tools/datagrid/static/js/show_query_tool';
+import { FakeLink, FakeNode } from '../fake_item';
 
 let pgAdmin = {
   Browser: {
@@ -60,7 +61,7 @@ let mtmDialog = jasmine.createSpyObj('mtmDialog', ['show']);
 
 let getDialog = (dialogName)=>{
   switch(dialogName) {
-  case 'entity_dialog': return tableDialog;
+  case 'table_dialog': return tableDialog;
   case 'onetomany_dialog': return otmDialog;
   case 'manytomany_dialog': return mtmDialog;
   }
@@ -93,19 +94,16 @@ describe('ERD BodyWidget', ()=>{
     title: 'postgres/postgres@PostgreSQL 12',
     trans_id: 110008,
   };
+  let newNode = new FakeNode({
+    columns: [{attnum: 0}, {attnum: 1}],
+  }, 'newid1');
 
   beforeAll(()=>{
     spyOn(erdModule, 'setPanelTitle');
     spyOn(ERDCore.prototype, 'repaint');
     spyOn(ERDCore.prototype, 'deserializeData');
-    spyOn(ERDCore.prototype, 'addNode').and.returnValue({
-      setSelected: ()=>{},
-      getColumns: ()=>([{attnum: 0}, {attnum: 1}]),
-      getID: ()=>'newid1',
-    });
-    spyOn(ERDCore.prototype, 'addLink').and.returnValue({
-      setSelected: ()=>{},
-    });
+    spyOn(ERDCore.prototype, 'addNode').and.returnValue(newNode);
+    spyOn(ERDCore.prototype, 'addLink').and.returnValue(new FakeLink());
     spyOn(alertify, 'confirm').and.callFake((arg1, arg2, okCallback)=>{
       okCallback();
     });
@@ -128,7 +126,7 @@ describe('ERD BodyWidget', ()=>{
 
   beforeEach(()=>{
     jasmineEnzyme();
-    body = mount(<BodyWidget params={params} pgAdmin={pgAdmin} pgWindow={pgWindow} getDialog={getDialog} transformToSupported={()=>{}} alertify={alertify}/>);
+    body = mount(<BodyWidget params={params} pgAdmin={pgAdmin} pgWindow={pgWindow} getDialog={getDialog} alertify={alertify}/>);
     bodyInstance = body.instance();
   });
 
@@ -225,18 +223,18 @@ describe('ERD BodyWidget', ()=>{
     });
   });
 
-  it('event editNode', (done)=>{
+  it('event editTable', (done)=>{
     let node = {key: 'value', getNote: ()=>'a note'};
-    spyOn(bodyInstance, 'addEditNode');
-    bodyInstance.diagram.fireEvent({node: node}, 'editNode', true);
+    spyOn(bodyInstance, 'addEditTable');
+    bodyInstance.diagram.fireEvent({node: node}, 'editTable', true);
     setTimeout(()=>{
-      expect(bodyInstance.addEditNode).toHaveBeenCalledWith(node);
+      expect(bodyInstance.addEditTable).toHaveBeenCalledWith(node);
       done();
     });
   });
 
   it('getDialog', ()=>{
-    bodyInstance.getDialog('entity_dialog')();
+    bodyInstance.getDialog('table_dialog')();
     expect(tableDialog.show).toHaveBeenCalled();
 
     bodyInstance.getDialog('onetomany_dialog')();
@@ -246,10 +244,20 @@ describe('ERD BodyWidget', ()=>{
     expect(mtmDialog.show).toHaveBeenCalled();
   });
 
-  it('addEditNode', ()=>{
+  it('addEditTable', ()=>{
+    let node1 = new FakeNode({'name': 'table1', schema: 'erd1', columns: [{name: 'col1', type: 'type1', attnum: 1}]}, 'id1');
+    let node2 = new FakeNode({'name': 'table2', schema: 'erd2', columns: [{name: 'col2', type: 'type2', attnum: 2}]}, 'id2');
+    let nodesDict = {
+      'id1': node1,
+      'id2': node2,
+    };
+    spyOn(bodyInstance.diagram, 'getModel').and.returnValue({
+      'getNodesDict': ()=>nodesDict,
+    });
+    spyOn(bodyInstance.diagram, 'addLink');
     /* New */
     tableDialog.show.calls.reset();
-    bodyInstance.addEditNode();
+    bodyInstance.addEditTable();
     expect(tableDialog.show).toHaveBeenCalled();
 
     let saveCallback = tableDialog.show.calls.mostRecent().args[7];
@@ -259,12 +267,9 @@ describe('ERD BodyWidget', ()=>{
 
     /* Existing */
     tableDialog.show.calls.reset();
-    let node = jasmine.createSpyObj('node',{
-      getSchemaTableName: ['erd1', 'table1'],
-      setData: null,
-      getData: null,
-    });
-    bodyInstance.addEditNode(node);
+    let node = new FakeNode({name: 'table1', schema: 'erd1'});
+    spyOn(node, 'setData');
+    bodyInstance.addEditTable(node);
     expect(tableDialog.show).toHaveBeenCalled();
 
     saveCallback = tableDialog.show.calls.mostRecent().args[7];
@@ -273,49 +278,44 @@ describe('ERD BodyWidget', ()=>{
     expect(node.setData).toHaveBeenCalledWith(newData);
   });
 
-  it('onEditNode', ()=>{
+  it('onEditTable', ()=>{
     let node = {key: 'value'};
-    spyOn(bodyInstance, 'addEditNode');
+    spyOn(bodyInstance, 'addEditTable');
     spyOn(bodyInstance.diagram, 'getSelectedNodes').and.returnValue([node]);
-    bodyInstance.onEditNode();
-    expect(bodyInstance.addEditNode).toHaveBeenCalledWith(node);
+    bodyInstance.onEditTable();
+    expect(bodyInstance.addEditTable).toHaveBeenCalledWith(node);
   });
 
   it('onAddNewNode', ()=>{
-    spyOn(bodyInstance, 'addEditNode');
+    spyOn(bodyInstance, 'addEditTable');
     bodyInstance.onAddNewNode();
-    expect(bodyInstance.addEditNode).toHaveBeenCalled();
+    expect(bodyInstance.addEditTable).toHaveBeenCalled();
   });
 
   it('onCloneNode', ()=>{
-    let node = jasmine.createSpyObj('node',{
-      getSchemaTableName: ['erd1', 'table1'],
-      setData: null,
-      getData: null,
-      cloneData: {key: 'value'},
-      getPosition: {x: 30, y: 30},
-    });
+    let node = new FakeNode({name: 'table1', schema: 'erd1'});
     spyOn(bodyInstance.diagram, 'getSelectedNodes').and.returnValue([node]);
     spyOn(bodyInstance.diagram, 'getNextTableName').and.returnValue('newtable1');
+    bodyInstance.diagram.addNode.calls.reset();
     bodyInstance.onCloneNode();
-    expect(bodyInstance.diagram.addNode).toHaveBeenCalledWith({key: 'value'}, [50, 50]);
+    let cloneArgs = bodyInstance.diagram.addNode.calls.argsFor(0);
+    expect(cloneArgs[0]).toEqual(jasmine.objectContaining({
+      name: 'newtable1',
+      schema: 'erd1',
+    }));
+    expect(cloneArgs[1]).toEqual([50, 50]);
   });
 
   it('onDeleteNode', (done)=>{
-    let node = jasmine.createSpyObj('node',{
-      getSchemaTableName: ['erd1', 'table1'],
-      setData: null,
-      getData: null,
-      cloneData: {key: 'value'},
-      getPosition: {x: 30, y: 30},
-      remove: null,
-      setSelected: null,
-    });
-    let link = jasmine.createSpyObj('link', {
-      remove: null,
-      setSelected: null,
-      getTargetPort: jasmine.createSpyObj('port', ['remove']),
-      getSourcePort: jasmine.createSpyObj('port', ['remove']),
+    let node = new FakeNode({name: 'table1', schema: 'erd1'});
+    spyOn(node, 'remove');
+    let link = new FakeLink({local_table_uid: 'tid1'});
+    spyOn(link, 'remove');
+    let nodesDict = {
+      'tid1': node
+    };
+    spyOn(bodyInstance.diagram, 'getModel').and.returnValue({
+      'getNodesDict': ()=>nodesDict,
     });
     spyOn(bodyInstance.diagram, 'getSelectedNodes').and.returnValue([node]);
     spyOn(bodyInstance.diagram, 'getSelectedLinks').and.returnValue([link]);
@@ -413,9 +413,17 @@ describe('ERD BodyWidget', ()=>{
   });
 
   it('onOneToManyClick', ()=>{
-    let node = jasmine.createSpyObj('node',{
-      getID: 'id1',
+    let node = new FakeNode({}, 'id1');
+    let node1 = new FakeNode({'name': 'table1', schema: 'erd1', columns: [{name: 'col1', type: 'type1', attnum: 1}]}, 'id1');
+    let node2 = new FakeNode({'name': 'table2', schema: 'erd2', columns: [{name: 'col2', type: 'type2', attnum: 2}]}, 'id2');
+    let nodesDict = {
+      'id1': node1,
+      'id2': node2,
+    };
+    spyOn(bodyInstance.diagram, 'getModel').and.returnValue({
+      'getNodesDict': ()=>nodesDict,
     });
+    spyOn(bodyInstance.diagram, 'addLink');
     spyOn(bodyInstance.diagram, 'getSelectedNodes').and.returnValue([node]);
 
     otmDialog.show.calls.reset();
@@ -423,15 +431,18 @@ describe('ERD BodyWidget', ()=>{
     expect(otmDialog.show).toHaveBeenCalled();
 
     let saveCallback = otmDialog.show.calls.mostRecent().args[4];
-    let newData = {key: 'value'};
+    let newData = {
+      local_table_uid: 'id1',
+      local_column_attnum: 1,
+      referenced_table_uid: 'id2',
+      referenced_column_attnum: 2,
+    };
     saveCallback(newData);
     expect(bodyInstance.diagram.addLink).toHaveBeenCalledWith(newData, 'onetomany');
   });
 
   it('onManyToManyClick', ()=>{
-    let node = jasmine.createSpyObj('node',{
-      getID: 'id1',
-    });
+    let node = new FakeNode({}, 'id1');
     spyOn(bodyInstance.diagram, 'getSelectedNodes').and.returnValue([node]);
 
     mtmDialog.show.calls.reset();
@@ -439,19 +450,12 @@ describe('ERD BodyWidget', ()=>{
     expect(mtmDialog.show).toHaveBeenCalled();
 
     /* onSave */
+    let node1 = new FakeNode({'name': 'table1', schema: 'erd1', columns: [{name: 'col1', type: 'type1', attnum: 1}]}, 'id1');
+    let node2 = new FakeNode({'name': 'table2', schema: 'erd2', columns: [{name: 'col2', type: 'type2', attnum: 2}]}, 'id2');
     let nodesDict = {
-      'id1': {
-        getID: ()=>'id1',
-        getData: ()=>({name: 'table1', schema: 'erd1'}),
-        getColumnAt: ()=>({name: 'col1', type: 'type1', attnum: 0}),
-        addPort: jasmine.createSpy('addPort').and.callFake((obj)=>obj),
-      },
-      'id2': {
-        getID: ()=>'id2',
-        getData: ()=>({name: 'table2', schema: 'erd2'}),
-        getColumnAt: ()=>({name: 'col2', type: 'type2', attnum: 1}),
-        addPort: jasmine.createSpy('addPort').and.callFake((obj)=>obj),
-      },
+      'id1': node1,
+      'id2': node2,
+      'newid1': newNode,
     };
     spyOn(bodyInstance.diagram, 'getModel').and.returnValue({
       'getNodesDict': ()=>nodesDict,
@@ -468,24 +472,21 @@ describe('ERD BodyWidget', ()=>{
     bodyInstance.diagram.addNode.calls.reset();
     bodyInstance.diagram.addLink.calls.reset();
     saveCallback(newData);
-    expect(bodyInstance.diagram.addNode).toHaveBeenCalledWith({
+    let tableData = bodyInstance.diagram.addNode.calls.argsFor(0)[0];
+    expect(tableData).toEqual(jasmine.objectContaining({
       name: 'table1_table2',
       schema: 'erd1',
-      columns: [
-        {
-          type: 'type1',
-          name: 'table1_col1',
-          is_primary_key: false,
-          attnum: 0,
-        },
-        {
-          type: 'type2',
-          name: 'table2_col2',
-          is_primary_key: false,
-          attnum: 1,
-        },
-      ],
-    });
+    }));
+    expect(tableData.columns[0]).toEqual(jasmine.objectContaining({
+      type: 'type1',
+      name: 'table1_col1',
+      attnum: 0,
+    }));
+    expect(tableData.columns[1]).toEqual(jasmine.objectContaining({
+      type: 'type2',
+      name: 'table2_col2',
+      attnum: 1,
+    }));
 
     let linkData = {
       local_table_uid: 'newid1',
diff --git a/web/regression/javascript/schema_ui_files/column.ui.spec.js b/web/regression/javascript/schema_ui_files/column.ui.spec.js
index a6528ab16..bde3aff27 100644
--- a/web/regression/javascript/schema_ui_files/column.ui.spec.js
+++ b/web/regression/javascript/schema_ui_files/column.ui.spec.js
@@ -202,13 +202,13 @@ describe('ColumnSchema', ()=>{
     expect(schemaObj.inSchemaWithColumnCheck(state)).toBe(true);
 
     schemaObj.nodeInfo = {};
-    expect(schemaObj.inSchemaWithColumnCheck(state)).toBe(true);
+    expect(schemaObj.inSchemaWithColumnCheck(state)).toBe(false);
   });
 
   it('editableCheckForTable', ()=>{
     let state = {};
     schemaObj.nodeInfo = {};
-    expect(schemaObj.editableCheckForTable(state)).toBe(false);
+    expect(schemaObj.editableCheckForTable(state)).toBe(true);
   });
 
   it('depChange', ()=>{
diff --git a/web/yarn.lock b/web/yarn.lock
index b92c49a2d..254a37a9d 100644
--- a/web/yarn.lock
+++ b/web/yarn.lock
@@ -1464,50 +1464,50 @@
   resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.9.0.tgz#32e63212293dd3efbb521cd35a5020ab66eaa546"
   integrity sha512-wjtKehFAIARq2OxK8j3JrggNlEslJfNuSm2ArteIbKyRMts2g0a7KzTxfRVNUM+O0gnBJ2hNV8nWPOYBgI1sew==
 
-"@projectstorm/geometry@^6.5.2":
-  version "6.5.2"
-  resolved "https://registry.yarnpkg.com/@projectstorm/geometry/-/geometry-6.5.2.tgz#76ccc7280a49c64953036aa96287f408981e5913"
-  integrity sha512-PGrcMXr6CkdH1DvcY+MDYzg6suWnOXehP8S69DhiEeWUFmQhKJSCAPEovdQOpohL6urlKaSNbDM8auUypFbTfw==
-
-"@projectstorm/react-canvas-core@^6.5.2":
-  version "6.5.2"
-  resolved "https://registry.yarnpkg.com/@projectstorm/react-canvas-core/-/react-canvas-core-6.5.2.tgz#65726df39c15487d9c6b23616cfa6b182d82fcbe"
-  integrity sha512-tFfWpaPZ71lMDFRL69jRFTjmYit6FKNpkAiI9sqYeH2I4Y7OjuxmCqYomlzh8ZSLVwKHtcI6Vd7hhoatEBupEQ==
-  dependencies:
-    "@projectstorm/geometry" "^6.5.2"
-
-"@projectstorm/react-diagrams-core@^6.5.2":
-  version "6.5.2"
-  resolved "https://registry.yarnpkg.com/@projectstorm/react-diagrams-core/-/react-diagrams-core-6.5.2.tgz#4c8c92ed288b2934de11c1a52fda72249b151932"
-  integrity sha512-7ganJGs7lcRB1sTvUs+MQ9RiSCGD+IHgISo45aS81+XFllO8u7uZRaPdIyObhz+khwZvMk2pWmXYPNJwGThOZQ==
-  dependencies:
-    "@projectstorm/geometry" "^6.5.2"
-    "@projectstorm/react-canvas-core" "^6.5.2"
-
-"@projectstorm/react-diagrams-defaults@^6.5.2":
-  version "6.5.2"
-  resolved "https://registry.yarnpkg.com/@projectstorm/react-diagrams-defaults/-/react-diagrams-defaults-6.5.2.tgz#084138e8b2ac2643bcfa115fb543f69c0eaf88f3"
-  integrity sha512-8+hAe88Lj7uBsugAT7f5SsjqxmjYfeBYwViaFpnIilmuYF/uXN0w/ns8Mcq2FE49wGOXtBoxFusoWmDWwgE+fQ==
-  dependencies:
-    "@projectstorm/react-diagrams-core" "^6.5.2"
-
-"@projectstorm/react-diagrams-routing@^6.5.2":
-  version "6.5.2"
-  resolved "https://registry.yarnpkg.com/@projectstorm/react-diagrams-routing/-/react-diagrams-routing-6.5.2.tgz#824dadbcd8c14c647829bdd4761afef69dec5622"
-  integrity sha512-pWsDmk/4hbx6Ii2Z3Uvd9dZ/xB9F7u66mGVGMWb3txxTT68Y6mwdVJRQFu/frm/Sk3sZv7gNf1EqadsilIh7vg==
-  dependencies:
-    "@projectstorm/geometry" "^6.5.2"
-    "@projectstorm/react-diagrams-core" "^6.5.2"
-    "@projectstorm/react-diagrams-defaults" "^6.5.2"
-
-"@projectstorm/react-diagrams@^6.4.2":
-  version "6.5.2"
-  resolved "https://registry.yarnpkg.com/@projectstorm/react-diagrams/-/react-diagrams-6.5.2.tgz#3f65a903b1853e51d68109a513d91d190d278864"
-  integrity sha512-1xlz1jVffWq5R7Oqj/BEY06Cf+2uLV5eEY6pGxuGFfp5SXeTNCSIS/khkbFou707Gor3D8MOqdBpZvF2NfoLmA==
-  dependencies:
-    "@projectstorm/react-diagrams-core" "^6.5.2"
-    "@projectstorm/react-diagrams-defaults" "^6.5.2"
-    "@projectstorm/react-diagrams-routing" "^6.5.2"
+"@projectstorm/geometry@^6.6.1":
+  version "6.6.1"
+  resolved "https://registry.yarnpkg.com/@projectstorm/geometry/-/geometry-6.6.1.tgz#4a42f5c8fdfcc3d951e73f5db7fe9546514acc3d"
+  integrity sha512-gWRkv+fm+VIpoffHzDHPmGYlEqx8xWGfE/JR7TXAZweNdjEIxyhT++hVlCJiFJS+/cGqgN3z+eP7PNjwZUPGRg==
+
+"@projectstorm/react-canvas-core@^6.6.1":
+  version "6.6.1"
+  resolved "https://registry.yarnpkg.com/@projectstorm/react-canvas-core/-/react-canvas-core-6.6.1.tgz#93cc6e70e986fe620b6fad6b597d3aa038075244"
+  integrity sha512-wAxEh4Wja2Au0QAuLqxJNaWpVxYIffTFUZhjH8wtW8MKCWS6W9RnP6upeC8QVQi29NS59UIX4wXNzb6e6ht5ww==
+  dependencies:
+    "@projectstorm/geometry" "^6.6.1"
+
+"@projectstorm/react-diagrams-core@^6.6.1":
+  version "6.6.1"
+  resolved "https://registry.yarnpkg.com/@projectstorm/react-diagrams-core/-/react-diagrams-core-6.6.1.tgz#f626c6253dd6f4b04c3256976b55377ffac2b1bb"
+  integrity sha512-TiDwpcH+t2b2tG/UHDQvhlyx3gOQRJXxTyNDo7p+430ikTrvz1f8uNe5Rt3SrzyqxeUazLFXYBgbGpEanqOykQ==
+  dependencies:
+    "@projectstorm/geometry" "^6.6.1"
+    "@projectstorm/react-canvas-core" "^6.6.1"
+
+"@projectstorm/react-diagrams-defaults@^6.6.1":
+  version "6.6.1"
+  resolved "https://registry.yarnpkg.com/@projectstorm/react-diagrams-defaults/-/react-diagrams-defaults-6.6.1.tgz#a97cdda56d7336b84775f76a925b90286ea2833d"
+  integrity sha512-FJu8BNBjvANVZ8N99WXS/f6Mu5/yMC4Pi55kTG3vq7o14tsVMcghosmxst5eoeL251O4I+ulNvQ/yCc1Mc5org==
+  dependencies:
+    "@projectstorm/react-diagrams-core" "^6.6.1"
+
+"@projectstorm/react-diagrams-routing@^6.6.1":
+  version "6.6.1"
+  resolved "https://registry.yarnpkg.com/@projectstorm/react-diagrams-routing/-/react-diagrams-routing-6.6.1.tgz#06b77ab1f94f4567391099ffe5e1d91db34408ff"
+  integrity sha512-m8akJynhanxmpc/A2U7bcgFxIMxsjb3zmYBRGFltVJve87mir8ACaH2gmiHYcAfgEHxdh+x7mCuUlfNP242Ytw==
+  dependencies:
+    "@projectstorm/geometry" "^6.6.1"
+    "@projectstorm/react-diagrams-core" "^6.6.1"
+    "@projectstorm/react-diagrams-defaults" "^6.6.1"
+
+"@projectstorm/react-diagrams@^6.6.1":
+  version "6.6.1"
+  resolved "https://registry.yarnpkg.com/@projectstorm/react-diagrams/-/react-diagrams-6.6.1.tgz#3af4007613f487ba58801cdcded955683b3f01c5"
+  integrity sha512-tLSXfEf/dGFUN8JCCRMrYyIBhhn+eVw24xQodmtcReJxQpKa31EWh9CmJ6UEg7xUnabMG9f2plOPyJqyFssGTA==
+  dependencies:
+    "@projectstorm/react-diagrams-core" "^6.6.1"
+    "@projectstorm/react-diagrams-defaults" "^6.6.1"
+    "@projectstorm/react-diagrams-routing" "^6.6.1"
 
 "@simonwep/pickr@^1.5.1":
   version "1.8.1"
