[ASTERIXDB-3259][MTD] Prepare metadata for DATABASE entity

- user model changes: no
- storage format changes: no
- interface changes: yes

Details:
Introduce MetadataIndexesProvider to guide tuple translators.

Change-Id: I1222cac112ae09028142cf2507a70f861684149a
Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/17772
Reviewed-by: Ali Alsuliman <ali.al.solaiman@gmail.com>
Reviewed-by: Wail Alkowaileet <wael.y.k@gmail.com>
Integration-Tests: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Tested-by: Ali Alsuliman <ali.al.solaiman@gmail.com>
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/nc/NCAppRuntimeContext.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/nc/NCAppRuntimeContext.java
index 6bccc44..630265c 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/nc/NCAppRuntimeContext.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/nc/NCAppRuntimeContext.java
@@ -466,17 +466,19 @@
 
     @Override
     public void initializeMetadata(boolean newUniverse, int partitionId) throws Exception {
-        LOGGER.info("Bootstrapping metadata");
-        MetadataNode.INSTANCE.initialize(this, ncExtensionManager.getMetadataTupleTranslatorProvider(),
-                ncExtensionManager.getMetadataExtensions(), partitionId);
+        LOGGER.info("Bootstrapping ({}) metadata in partition {}", newUniverse ? "new" : "existing", partitionId);
+        MetadataNode.INSTANCE.initialize(this, ncExtensionManager.getMetadataIndexesProvider(),
+                ncExtensionManager.getMetadataTupleTranslatorProvider(), ncExtensionManager.getMetadataExtensions(),
+                partitionId);
 
         // This is a special case, we just give the metadataNode directly.
         // This way we can delay the registration of the metadataNode until
         // it is completely initialized.
         MetadataManager.initialize(getAsterixStateProxies(), MetadataNode.INSTANCE);
-        MetadataBootstrap.startUniverse(getServiceContext(), newUniverse);
+        MetadataBootstrap.startUniverse(getServiceContext(), newUniverse,
+                ncExtensionManager.getMetadataIndexesProvider());
         MetadataBootstrap.startDDLRecovery();
-        ncExtensionManager.initializeMetadata(getServiceContext());
+        ncExtensionManager.initializeMetadata(getServiceContext(), ncExtensionManager.getMetadataIndexesProvider());
         LOGGER.info("Metadata node bound");
     }
 
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/nc/NCExtensionManager.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/nc/NCExtensionManager.java
index 5c8e3b1..6c037d2 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/nc/NCExtensionManager.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/nc/NCExtensionManager.java
@@ -31,6 +31,7 @@
 import org.apache.asterix.compiler.provider.SqlppCompilationProvider;
 import org.apache.asterix.metadata.api.IMetadataExtension;
 import org.apache.asterix.metadata.api.INCExtensionManager;
+import org.apache.asterix.metadata.bootstrap.MetadataIndexesProvider;
 import org.apache.asterix.metadata.entitytupletranslators.MetadataTupleTranslatorProvider;
 import org.apache.asterix.utils.ExtensionUtil;
 import org.apache.hyracks.algebricks.common.utils.Pair;
@@ -45,28 +46,30 @@
 
     private final ILangCompilationProvider sqlppCompilationProvider;
     private final MetadataTupleTranslatorProvider tupleTranslatorProvider;
+    private final MetadataIndexesProvider metadataIndexesProvider;
     private final List<IMetadataExtension> mdExtensions;
 
     /**
      * Initialize {@code CCExtensionManager} from configuration
      *
      * @param list
-     *            list of user configured extensions
+     *         list of user configured extensions
+     * @param ncServiceCtx
      * @throws InstantiationException
-     *             if an extension couldn't be created
+     *         if an extension couldn't be created
      * @throws IllegalAccessException
-     *             if user doesn't have enough acess priveleges
+     *         if user doesn't have enough acess priveleges
      * @throws ClassNotFoundException
-     *             if a class was not found
+     *         if a class was not found
      * @throws HyracksDataException
-     *             if two extensions conlict with each other
+     *         if two extensions conlict with each other
      */
-    public NCExtensionManager(List<AsterixExtension> list)
+    public NCExtensionManager(List<AsterixExtension> list, INCServiceContext ncServiceCtx)
             throws InstantiationException, IllegalAccessException, ClassNotFoundException, HyracksDataException {
-        Pair<ExtensionId, ILangCompilationProvider> aqlcp = null;
         Pair<ExtensionId, ILangCompilationProvider> sqlppcp = null;
         IMetadataExtension tupleTranslatorProviderExtension = null;
         mdExtensions = new ArrayList<>();
+        MetadataIndexesProvider mdIndexesProvider = new MetadataIndexesProvider(ncServiceCtx);
         if (list != null) {
             for (AsterixExtension extensionConf : list) {
                 IExtension extension = (IExtension) Class.forName(extensionConf.getClassName()).newInstance();
@@ -80,8 +83,9 @@
                     case METADATA:
                         IMetadataExtension mde = (IMetadataExtension) extension;
                         mdExtensions.add(mde);
-                        tupleTranslatorProviderExtension =
-                                ExtensionUtil.extendTupleTranslatorProvider(tupleTranslatorProviderExtension, mde);
+                        //TODO(DB) clean up
+                        tupleTranslatorProviderExtension = ExtensionUtil.extendTupleTranslatorProvider(
+                                tupleTranslatorProviderExtension, mde, mdIndexesProvider);
                         break;
                     default:
                         break;
@@ -89,8 +93,14 @@
             }
         }
         this.sqlppCompilationProvider = sqlppcp == null ? new SqlppCompilationProvider() : sqlppcp.second;
-        this.tupleTranslatorProvider = tupleTranslatorProviderExtension == null ? new MetadataTupleTranslatorProvider()
-                : tupleTranslatorProviderExtension.getMetadataTupleTranslatorProvider();
+        if (tupleTranslatorProviderExtension == null) {
+            this.metadataIndexesProvider = mdIndexesProvider;
+            this.tupleTranslatorProvider = new MetadataTupleTranslatorProvider(metadataIndexesProvider);
+        } else {
+            this.metadataIndexesProvider = tupleTranslatorProviderExtension.getMetadataIndexesProvider(ncServiceCtx);
+            this.tupleTranslatorProvider =
+                    tupleTranslatorProviderExtension.getMetadataTupleTranslatorProvider(metadataIndexesProvider);
+        }
     }
 
     public ILangCompilationProvider getCompilationProvider(ILangExtension.Language lang) {
@@ -111,18 +121,25 @@
         return tupleTranslatorProvider;
     }
 
+    @Override
+    public MetadataIndexesProvider getMetadataIndexesProvider() {
+        return metadataIndexesProvider;
+    }
+
     /**
      * Called on bootstrap of metadata node allowing extensions to instantiate their Metadata artifacts
      *
      * @param ncServiceCtx
-     *            the node controller service context
+     *         the node controller service context
+     * @param mdIndexesProvider
      * @throws HyracksDataException
      */
-    public void initializeMetadata(INCServiceContext ncServiceCtx) throws HyracksDataException {
+    public void initializeMetadata(INCServiceContext ncServiceCtx, MetadataIndexesProvider mdIndexesProvider)
+            throws HyracksDataException {
         if (mdExtensions != null) {
             for (IMetadataExtension mdExtension : mdExtensions) {
                 try {
-                    mdExtension.initializeMetadata(ncServiceCtx);
+                    mdExtension.initializeMetadata(ncServiceCtx, mdIndexesProvider);
                 } catch (RemoteException | ACIDException e) {
                     throw HyracksDataException.create(e);
                 }
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/hyracks/bootstrap/NCApplication.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/hyracks/bootstrap/NCApplication.java
index a223e0d..b15ae3e 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/hyracks/bootstrap/NCApplication.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/hyracks/bootstrap/NCApplication.java
@@ -154,7 +154,7 @@
         }
         MetadataBuiltinFunctions.init();
 
-        ncExtensionManager = new NCExtensionManager(new ArrayList<>(getExtensions()));
+        ncExtensionManager = new NCExtensionManager(new ArrayList<>(getExtensions()), ncServiceCtx);
         runtimeContext = createNCApplicationContext(ncServiceCtx, ncExtensionManager, getPropertiesFactory());
         MetadataProperties metadataProperties = runtimeContext.getMetadataProperties();
         if (!metadataProperties.getNodeNames().contains(this.ncServiceCtx.getNodeId())) {
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/utils/ExtensionUtil.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/utils/ExtensionUtil.java
index c3d1ac5..d29a37c 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/utils/ExtensionUtil.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/utils/ExtensionUtil.java
@@ -26,6 +26,7 @@
 import org.apache.asterix.common.exceptions.RuntimeDataException;
 import org.apache.asterix.compiler.provider.ILangCompilationProvider;
 import org.apache.asterix.metadata.api.IMetadataExtension;
+import org.apache.asterix.metadata.bootstrap.MetadataIndexesProvider;
 import org.apache.asterix.om.functions.IFunctionManager;
 import org.apache.asterix.translator.IStatementExecutorFactory;
 import org.apache.hyracks.algebricks.common.utils.Pair;
@@ -106,20 +107,21 @@
      * Validates no extension conflict and extends tuple translator provider
      *
      * @param metadataExtension
-     *            place holder for tuple translator provider extension
+     *         place holder for tuple translator provider extension
      * @param mde
-     *            user defined metadata extension
+     *         user defined metadata extension
+     * @param metadataIndexesProvider
      * @return the metadata extension if the extension defines a metadata tuple translator, null otherwise
      * @throws RuntimeDataException
-     *             if an extension conflict was detected
+     *         if an extension conflict was detected
      */
     public static IMetadataExtension extendTupleTranslatorProvider(IMetadataExtension metadataExtension,
-            IMetadataExtension mde) throws RuntimeDataException {
+            IMetadataExtension mde, MetadataIndexesProvider metadataIndexesProvider) throws RuntimeDataException {
         if (metadataExtension != null) {
             throw new RuntimeDataException(ErrorCode.EXTENSION_COMPONENT_CONFLICT, metadataExtension.getId(),
                     mde.getId(), IMetadataExtension.class.getSimpleName());
         }
-        return mde.getMetadataTupleTranslatorProvider() == null ? null : mde;
+        return mde.getMetadataTupleTranslatorProvider(metadataIndexesProvider) == null ? null : mde;
     }
 
     /**
diff --git a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/metadata/MetadataTxnTest.java b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/metadata/MetadataTxnTest.java
index b34f5c6..aaf9fcb 100644
--- a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/metadata/MetadataTxnTest.java
+++ b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/metadata/MetadataTxnTest.java
@@ -40,7 +40,7 @@
 import org.apache.asterix.metadata.MetadataTransactionContext;
 import org.apache.asterix.metadata.api.IMetadataIndex;
 import org.apache.asterix.metadata.bootstrap.MetadataBuiltinEntities;
-import org.apache.asterix.metadata.bootstrap.MetadataPrimaryIndexes;
+import org.apache.asterix.metadata.bootstrap.NodeGroupEntity;
 import org.apache.asterix.metadata.declared.MetadataProvider;
 import org.apache.asterix.metadata.entities.Dataset;
 import org.apache.asterix.metadata.entities.NodeGroup;
@@ -271,7 +271,7 @@
         INcApplicationContext appCtx = (INcApplicationContext) integrationUtil.ncs[0].getApplicationContext();
         IDatasetLifecycleManager dlcm = appCtx.getDatasetLifecycleManager();
         dlcm.flushAllDatasets();
-        IMetadataIndex idx = MetadataPrimaryIndexes.NODEGROUP_DATASET;
+        IMetadataIndex idx = NodeGroupEntity.of(false).getIndex();
         DatasetInfo datasetInfo = dlcm.getDatasetInfo(idx.getDatasetId().getId());
         AbstractLSMIndex index = (AbstractLSMIndex) appCtx.getDatasetLifecycleManager()
                 .getIndex(idx.getDatasetId().getId(), idx.getResourceId());
diff --git a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/storage/LsmIndexLifecycleTest.java b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/storage/LsmIndexLifecycleTest.java
index 15f1730..22dcecb 100644
--- a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/storage/LsmIndexLifecycleTest.java
+++ b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/storage/LsmIndexLifecycleTest.java
@@ -25,7 +25,7 @@
 import org.apache.asterix.common.config.GlobalConfig;
 import org.apache.asterix.common.context.DatasetInfo;
 import org.apache.asterix.metadata.api.IMetadataIndex;
-import org.apache.asterix.metadata.bootstrap.MetadataPrimaryIndexes;
+import org.apache.asterix.metadata.bootstrap.DatasetEntity;
 import org.apache.asterix.test.common.TestExecutor;
 import org.apache.asterix.testframework.context.TestCaseContext;
 import org.apache.hyracks.storage.am.lsm.common.impls.AbstractLSMIndex;
@@ -57,7 +57,7 @@
         TestDataUtil.createIdOnlyDataset(datasetName);
         INcApplicationContext appCtx = (INcApplicationContext) (integrationUtil.ncs[0].getApplicationContext());
         IDatasetLifecycleManager dlcm = appCtx.getDatasetLifecycleManager();
-        IMetadataIndex dsIdx = MetadataPrimaryIndexes.DATASET_DATASET;
+        IMetadataIndex dsIdx = DatasetEntity.of(false).getIndex();
         DatasetInfo datasetInfo = dlcm.getDatasetInfo(dsIdx.getDatasetId().getId());
         // flush to ensure multiple disk components
         dlcm.flushAllDatasets();
diff --git a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/metadata/MetadataIndexImmutableProperties.java b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/metadata/MetadataIndexImmutableProperties.java
index a8cd14f..3426d74 100644
--- a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/metadata/MetadataIndexImmutableProperties.java
+++ b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/metadata/MetadataIndexImmutableProperties.java
@@ -23,7 +23,7 @@
     public static final int FIRST_AVAILABLE_EXTENSION_METADATA_DATASET_ID = 52;
     public static final int FIRST_AVAILABLE_USER_DATASET_ID = 100;
     public static final int METADATA_DATASETS_PARTITIONS = 1;
-    public static final int METADATA_DATASETS_COUNT = 15;
+    public static final int METADATA_DATASETS_COUNT = 17;
 
     private final String indexName;
     private final int datasetId;
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/MetadataNode.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/MetadataNode.java
index b40a4eb..c0075ec 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/MetadataNode.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/MetadataNode.java
@@ -61,7 +61,7 @@
 import org.apache.asterix.metadata.api.IMetadataIndex;
 import org.apache.asterix.metadata.api.IMetadataNode;
 import org.apache.asterix.metadata.api.IValueExtractor;
-import org.apache.asterix.metadata.bootstrap.MetadataPrimaryIndexes;
+import org.apache.asterix.metadata.bootstrap.MetadataIndexesProvider;
 import org.apache.asterix.metadata.entities.CompactionPolicy;
 import org.apache.asterix.metadata.entities.Dataset;
 import org.apache.asterix.metadata.entities.DatasourceAdapter;
@@ -161,6 +161,7 @@
     private int metadataStoragePartition;
     private transient CachingTxnIdFactory txnIdFactory;
     // core only
+    private transient MetadataIndexesProvider mdIndexesProvider;
     private transient MetadataTupleTranslatorProvider tupleTranslatorProvider;
     // extension only
     private Map<ExtensionMetadataDatasetId, ExtensionMetadataDataset<?>> extensionDatasets;
@@ -173,9 +174,10 @@
         super();
     }
 
-    public void initialize(INcApplicationContext runtimeContext,
+    public void initialize(INcApplicationContext runtimeContext, MetadataIndexesProvider metadataIndexesProvider,
             MetadataTupleTranslatorProvider tupleTranslatorProvider, List<IMetadataExtension> metadataExtensions,
             int partitionId) {
+        this.mdIndexesProvider = metadataIndexesProvider;
         this.tupleTranslatorProvider = tupleTranslatorProvider;
         this.transactionSubsystem = runtimeContext.getTransactionSubsystem();
         this.datasetLifecycleManager = runtimeContext.getDatasetLifecycleManager();
@@ -183,7 +185,8 @@
         if (metadataExtensions != null) {
             extensionDatasets = new HashMap<>();
             for (IMetadataExtension metadataExtension : metadataExtensions) {
-                for (ExtensionMetadataDataset<?> extensionIndex : metadataExtension.getExtensionIndexes()) {
+                for (ExtensionMetadataDataset<?> extensionIndex : metadataExtension
+                        .getExtensionIndexes(metadataIndexesProvider)) {
                     extensionDatasets.put(extensionIndex.getId(), extensionIndex);
                 }
             }
@@ -351,7 +354,7 @@
         try {
             DataverseTupleTranslator tupleReaderWriter = tupleTranslatorProvider.getDataverseTupleTranslator(true);
             ITupleReference tuple = tupleReaderWriter.getTupleFromMetadataEntity(dataverse);
-            insertTupleIntoIndex(txnId, MetadataPrimaryIndexes.DATAVERSE_DATASET, tuple);
+            insertTupleIntoIndex(txnId, mdIndexesProvider.getDataverseEntity().getIndex(), tuple);
         } catch (HyracksDataException e) {
             if (e.matches(ErrorCode.DUPLICATE_KEY)) {
                 throw new AsterixException(org.apache.asterix.common.exceptions.ErrorCode.DATAVERSE_EXISTS, e,
@@ -368,7 +371,7 @@
             // Insert into the 'dataset' dataset.
             DatasetTupleTranslator tupleReaderWriter = tupleTranslatorProvider.getDatasetTupleTranslator(true);
             ITupleReference datasetTuple = tupleReaderWriter.getTupleFromMetadataEntity(dataset);
-            insertTupleIntoIndex(txnId, MetadataPrimaryIndexes.DATASET_DATASET, datasetTuple);
+            insertTupleIntoIndex(txnId, mdIndexesProvider.getDatasetEntity().getIndex(), datasetTuple);
             if (dataset.getDatasetType() == DatasetType.INTERNAL) {
                 // Add the primary index for the dataset.
                 InternalDatasetDetails id = (InternalDatasetDetails) dataset.getDatasetDetails();
@@ -392,7 +395,7 @@
         try {
             IndexTupleTranslator tupleWriter = tupleTranslatorProvider.getIndexTupleTranslator(txnId, this, true);
             ITupleReference tuple = tupleWriter.getTupleFromMetadataEntity(index);
-            insertTupleIntoIndex(txnId, MetadataPrimaryIndexes.INDEX_DATASET, tuple);
+            insertTupleIntoIndex(txnId, mdIndexesProvider.getIndexEntity().getIndex(), tuple);
         } catch (HyracksDataException e) {
             if (e.matches(ErrorCode.DUPLICATE_KEY)) {
                 throw new AsterixException(org.apache.asterix.common.exceptions.ErrorCode.INDEX_EXISTS, e,
@@ -408,7 +411,7 @@
         try {
             NodeTupleTranslator tupleReaderWriter = tupleTranslatorProvider.getNodeTupleTranslator(true);
             ITupleReference tuple = tupleReaderWriter.getTupleFromMetadataEntity(node);
-            insertTupleIntoIndex(txnId, MetadataPrimaryIndexes.NODE_DATASET, tuple);
+            insertTupleIntoIndex(txnId, mdIndexesProvider.getNodeEntity().getIndex(), tuple);
         } catch (HyracksDataException e) {
             if (e.matches(ErrorCode.DUPLICATE_KEY)) {
                 throw new AsterixException(org.apache.asterix.common.exceptions.ErrorCode.NODE_EXISTS, e,
@@ -424,7 +427,7 @@
         try {
             NodeGroupTupleTranslator tupleReaderWriter = tupleTranslatorProvider.getNodeGroupTupleTranslator(true);
             ITupleReference tuple = tupleReaderWriter.getTupleFromMetadataEntity(nodeGroup);
-            modifyMetadataIndex(modificationOp, txnId, MetadataPrimaryIndexes.NODEGROUP_DATASET, tuple);
+            modifyMetadataIndex(modificationOp, txnId, mdIndexesProvider.getNodeGroupEntity().getIndex(), tuple);
         } catch (HyracksDataException e) {
             if (e.matches(ErrorCode.DUPLICATE_KEY)) {
                 throw new AsterixException(org.apache.asterix.common.exceptions.ErrorCode.NODEGROUP_EXISTS, e,
@@ -441,7 +444,7 @@
             DatatypeTupleTranslator tupleReaderWriter =
                     tupleTranslatorProvider.getDataTypeTupleTranslator(txnId, this, true);
             ITupleReference tuple = tupleReaderWriter.getTupleFromMetadataEntity(datatype);
-            insertTupleIntoIndex(txnId, MetadataPrimaryIndexes.DATATYPE_DATASET, tuple);
+            insertTupleIntoIndex(txnId, mdIndexesProvider.getDatatypeEntity().getIndex(), tuple);
         } catch (HyracksDataException e) {
             if (e.matches(ErrorCode.DUPLICATE_KEY)) {
                 throw new AsterixException(org.apache.asterix.common.exceptions.ErrorCode.TYPE_EXISTS, e,
@@ -459,7 +462,7 @@
             FunctionTupleTranslator tupleReaderWriter =
                     tupleTranslatorProvider.getFunctionTupleTranslator(txnId, this, true);
             ITupleReference functionTuple = tupleReaderWriter.getTupleFromMetadataEntity(function);
-            insertTupleIntoIndex(txnId, MetadataPrimaryIndexes.FUNCTION_DATASET, functionTuple);
+            insertTupleIntoIndex(txnId, mdIndexesProvider.getFunctionEntity().getIndex(), functionTuple);
         } catch (HyracksDataException e) {
             if (e.matches(ErrorCode.DUPLICATE_KEY)) {
                 throw new AsterixException(org.apache.asterix.common.exceptions.ErrorCode.FUNCTION_EXISTS, e,
@@ -487,7 +490,8 @@
             IValueExtractor<FullTextFilterMetadataEntity> valueExtractor =
                     new MetadataEntityValueExtractor<>(translator);
             List<FullTextFilterMetadataEntity> results = new ArrayList<>();
-            searchIndex(txnId, MetadataPrimaryIndexes.FULL_TEXT_FILTER_DATASET, searchKey, valueExtractor, results);
+            searchIndex(txnId, mdIndexesProvider.getFullTextFilterEntity().getIndex(), searchKey, valueExtractor,
+                    results);
             if (results.isEmpty()) {
                 return null;
             }
@@ -510,7 +514,7 @@
         }
         try {
             ITupleReference key = createTuple(dataverseName.getCanonicalForm(), filterName);
-            deleteTupleFromIndex(txnId, MetadataPrimaryIndexes.FULL_TEXT_FILTER_DATASET, key);
+            deleteTupleFromIndex(txnId, mdIndexesProvider.getFullTextFilterEntity().getIndex(), key);
         } catch (HyracksDataException e) {
             throw new AlgebricksException(e);
         }
@@ -522,7 +526,7 @@
             FullTextConfigMetadataEntityTupleTranslator tupleReaderWriter =
                     tupleTranslatorProvider.getFullTextConfigTupleTranslator(true);
             ITupleReference configTuple = tupleReaderWriter.getTupleFromMetadataEntity(config);
-            insertTupleIntoIndex(txnId, MetadataPrimaryIndexes.FULL_TEXT_CONFIG_DATASET, configTuple);
+            insertTupleIntoIndex(txnId, mdIndexesProvider.getFullTextConfigEntity().getIndex(), configTuple);
         } catch (HyracksDataException e) {
             throw new AlgebricksException(e);
         }
@@ -534,7 +538,7 @@
             FullTextFilterMetadataEntityTupleTranslator tupleReaderWriter =
                     tupleTranslatorProvider.getFullTextFilterTupleTranslator(true);
             ITupleReference filterTuple = tupleReaderWriter.getTupleFromMetadataEntity(filter);
-            insertTupleIntoIndex(txnId, MetadataPrimaryIndexes.FULL_TEXT_FILTER_DATASET, filterTuple);
+            insertTupleIntoIndex(txnId, mdIndexesProvider.getFullTextFilterEntity().getIndex(), filterTuple);
         } catch (HyracksDataException e) {
             throw new AlgebricksException(e);
         }
@@ -562,7 +566,8 @@
             searchKey = createTuple(dataverseName.getCanonicalForm(), configName);
             IValueExtractor<FullTextConfigMetadataEntity> valueExtractor =
                     new MetadataEntityValueExtractor<>(translator);
-            searchIndex(txnId, MetadataPrimaryIndexes.FULL_TEXT_CONFIG_DATASET, searchKey, valueExtractor, results);
+            searchIndex(txnId, mdIndexesProvider.getFullTextConfigEntity().getIndex(), searchKey, valueExtractor,
+                    results);
         } catch (HyracksDataException e) {
             throw new AlgebricksException(e);
         }
@@ -589,7 +594,7 @@
 
         try {
             ITupleReference key = createTuple(dataverseName.getCanonicalForm(), configName);
-            deleteTupleFromIndex(txnId, MetadataPrimaryIndexes.FULL_TEXT_CONFIG_DATASET, key);
+            deleteTupleFromIndex(txnId, mdIndexesProvider.getFullTextConfigEntity().getIndex(), key);
         } catch (HyracksDataException e) {
             throw new AlgebricksException(e);
         }
@@ -759,8 +764,9 @@
             // Delete the dataverse entry from the 'dataverse' dataset.
             // As a side effect, acquires an S lock on the 'dataverse' dataset on behalf of txnId.
             ITupleReference searchKey = createTuple(dataverseName);
-            ITupleReference tuple = getTupleToBeDeleted(txnId, MetadataPrimaryIndexes.DATAVERSE_DATASET, searchKey);
-            deleteTupleFromIndex(txnId, MetadataPrimaryIndexes.DATAVERSE_DATASET, tuple);
+            ITupleReference tuple =
+                    getTupleToBeDeleted(txnId, mdIndexesProvider.getDataverseEntity().getIndex(), searchKey);
+            deleteTupleFromIndex(txnId, mdIndexesProvider.getDataverseEntity().getIndex(), tuple);
         } catch (HyracksDataException e) {
             if (e.matches(ErrorCode.UPDATE_OR_DELETE_NON_EXISTENT_KEY)) {
                 throw new AsterixException(org.apache.asterix.common.exceptions.ErrorCode.UNKNOWN_DATAVERSE, e,
@@ -805,7 +811,7 @@
             // lock on the 'dataset' dataset.
             ITupleReference datasetTuple = null;
             try {
-                datasetTuple = getTupleToBeDeleted(txnId, MetadataPrimaryIndexes.DATASET_DATASET, searchKey);
+                datasetTuple = getTupleToBeDeleted(txnId, mdIndexesProvider.getDatasetEntity().getIndex(), searchKey);
 
                 switch (dataset.getDatasetType()) {
                     case INTERNAL:
@@ -846,7 +852,7 @@
                     throw new AlgebricksException(hde);
                 }
             } finally {
-                deleteTupleFromIndex(txnId, MetadataPrimaryIndexes.DATASET_DATASET, datasetTuple);
+                deleteTupleFromIndex(txnId, mdIndexesProvider.getDatasetEntity().getIndex(), datasetTuple);
             }
         } catch (HyracksDataException e) {
             throw new AlgebricksException(e);
@@ -860,8 +866,9 @@
             ITupleReference searchKey = createTuple(dataverseName, datasetName, indexName);
             // Searches the index for the tuple to be deleted. Acquires an S
             // lock on the 'index' dataset.
-            ITupleReference tuple = getTupleToBeDeleted(txnId, MetadataPrimaryIndexes.INDEX_DATASET, searchKey);
-            deleteTupleFromIndex(txnId, MetadataPrimaryIndexes.INDEX_DATASET, tuple);
+            ITupleReference tuple =
+                    getTupleToBeDeleted(txnId, mdIndexesProvider.getIndexEntity().getIndex(), searchKey);
+            deleteTupleFromIndex(txnId, mdIndexesProvider.getIndexEntity().getIndex(), tuple);
         } catch (HyracksDataException e) {
             if (e.matches(ErrorCode.UPDATE_OR_DELETE_NON_EXISTENT_KEY)) {
                 throw new AsterixException(org.apache.asterix.common.exceptions.ErrorCode.UNKNOWN_INDEX, e, indexName);
@@ -887,8 +894,9 @@
             ITupleReference searchKey = createTuple(nodeGroupName);
             // Searches the index for the tuple to be deleted. Acquires an S
             // lock on the 'nodegroup' dataset.
-            ITupleReference tuple = getTupleToBeDeleted(txnId, MetadataPrimaryIndexes.NODEGROUP_DATASET, searchKey);
-            deleteTupleFromIndex(txnId, MetadataPrimaryIndexes.NODEGROUP_DATASET, tuple);
+            ITupleReference tuple =
+                    getTupleToBeDeleted(txnId, mdIndexesProvider.getNodeGroupEntity().getIndex(), searchKey);
+            deleteTupleFromIndex(txnId, mdIndexesProvider.getNodeGroupEntity().getIndex(), tuple);
             return true;
         } catch (HyracksDataException e) {
             if (e.matches(ErrorCode.UPDATE_OR_DELETE_NON_EXISTENT_KEY)) {
@@ -915,10 +923,11 @@
             ITupleReference searchKey = createTuple(dataverseName, datatypeName);
             // Searches the index for the tuple to be deleted. Acquires an S
             // lock on the 'datatype' dataset.
-            ITupleReference tuple = getTupleToBeDeleted(txnId, MetadataPrimaryIndexes.DATATYPE_DATASET, searchKey);
+            ITupleReference tuple =
+                    getTupleToBeDeleted(txnId, mdIndexesProvider.getDatatypeEntity().getIndex(), searchKey);
             // Get nested types
             List<String> nestedTypes = getNestedComplexDatatypeNamesForThisDatatype(txnId, dataverseName, datatypeName);
-            deleteTupleFromIndex(txnId, MetadataPrimaryIndexes.DATATYPE_DATASET, tuple);
+            deleteTupleFromIndex(txnId, mdIndexesProvider.getDatatypeEntity().getIndex(), tuple);
             for (String nestedType : nestedTypes) {
                 Datatype dt = getDatatype(txnId, dataverseName, nestedType);
                 if (dt != null && dt.getIsAnonymous()) {
@@ -941,8 +950,9 @@
             ITupleReference searchKey = createTuple(dataverseName, datatypeName);
             // Searches the index for the tuple to be deleted. Acquires an S
             // lock on the 'datatype' dataset.
-            ITupleReference tuple = getTupleToBeDeleted(txnId, MetadataPrimaryIndexes.DATATYPE_DATASET, searchKey);
-            deleteTupleFromIndex(txnId, MetadataPrimaryIndexes.DATATYPE_DATASET, tuple);
+            ITupleReference tuple =
+                    getTupleToBeDeleted(txnId, mdIndexesProvider.getDatatypeEntity().getIndex(), searchKey);
+            deleteTupleFromIndex(txnId, mdIndexesProvider.getDatatypeEntity().getIndex(), tuple);
         } catch (HyracksDataException e) {
             if (e.matches(ErrorCode.UPDATE_OR_DELETE_NON_EXISTENT_KEY)) {
                 throw new AsterixException(org.apache.asterix.common.exceptions.ErrorCode.UNKNOWN_TYPE, e,
@@ -964,7 +974,7 @@
             DataverseTupleTranslator tupleReaderWriter = tupleTranslatorProvider.getDataverseTupleTranslator(false);
             IValueExtractor<Dataverse> valueExtractor = new MetadataEntityValueExtractor<>(tupleReaderWriter);
             List<Dataverse> results = new ArrayList<>();
-            searchIndex(txnId, MetadataPrimaryIndexes.DATAVERSE_DATASET, null, valueExtractor, results);
+            searchIndex(txnId, mdIndexesProvider.getDataverseEntity().getIndex(), null, valueExtractor, results);
             return results;
         } catch (HyracksDataException e) {
             throw new AlgebricksException(e);
@@ -978,7 +988,7 @@
             DataverseTupleTranslator tupleReaderWriter = tupleTranslatorProvider.getDataverseTupleTranslator(false);
             IValueExtractor<Dataverse> valueExtractor = new MetadataEntityValueExtractor<>(tupleReaderWriter);
             List<Dataverse> results = new ArrayList<>();
-            searchIndex(txnId, MetadataPrimaryIndexes.DATAVERSE_DATASET, searchKey, valueExtractor, results);
+            searchIndex(txnId, mdIndexesProvider.getDataverseEntity().getIndex(), searchKey, valueExtractor, results);
             if (results.isEmpty()) {
                 return null;
             }
@@ -995,7 +1005,7 @@
             DatasetTupleTranslator tupleReaderWriter = tupleTranslatorProvider.getDatasetTupleTranslator(false);
             IValueExtractor<Dataset> valueExtractor = new MetadataEntityValueExtractor<>(tupleReaderWriter);
             List<Dataset> results = new ArrayList<>();
-            searchIndex(txnId, MetadataPrimaryIndexes.DATASET_DATASET, searchKey, valueExtractor, results);
+            searchIndex(txnId, mdIndexesProvider.getDatasetEntity().getIndex(), searchKey, valueExtractor, results);
             return results;
         } catch (HyracksDataException e) {
             throw new AlgebricksException(e);
@@ -1009,7 +1019,7 @@
             FeedTupleTranslator tupleReaderWriter = tupleTranslatorProvider.getFeedTupleTranslator(false);
             IValueExtractor<Feed> valueExtractor = new MetadataEntityValueExtractor<>(tupleReaderWriter);
             List<Feed> results = new ArrayList<>();
-            searchIndex(txnId, MetadataPrimaryIndexes.FEED_DATASET, searchKey, valueExtractor, results);
+            searchIndex(txnId, mdIndexesProvider.getFeedEntity().getIndex(), searchKey, valueExtractor, results);
             return results;
         } catch (HyracksDataException e) {
             throw new AlgebricksException(e);
@@ -1023,7 +1033,7 @@
             LibraryTupleTranslator tupleReaderWriter = tupleTranslatorProvider.getLibraryTupleTranslator(false);
             IValueExtractor<Library> valueExtractor = new MetadataEntityValueExtractor<>(tupleReaderWriter);
             List<Library> results = new ArrayList<>();
-            searchIndex(txnId, MetadataPrimaryIndexes.LIBRARY_DATASET, searchKey, valueExtractor, results);
+            searchIndex(txnId, mdIndexesProvider.getLibraryEntity().getIndex(), searchKey, valueExtractor, results);
             return results;
         } catch (HyracksDataException e) {
             throw new AlgebricksException(e);
@@ -1037,7 +1047,7 @@
                     tupleTranslatorProvider.getDataTypeTupleTranslator(txnId, this, false);
             IValueExtractor<Datatype> valueExtractor = new MetadataEntityValueExtractor<>(tupleReaderWriter);
             List<Datatype> results = new ArrayList<>();
-            searchIndex(txnId, MetadataPrimaryIndexes.DATATYPE_DATASET, searchKey, valueExtractor, results);
+            searchIndex(txnId, mdIndexesProvider.getDatatypeEntity().getIndex(), searchKey, valueExtractor, results);
             return results;
         } catch (HyracksDataException e) {
             throw new AlgebricksException(e);
@@ -1053,7 +1063,8 @@
                 new MetadataEntityValueExtractor<>(tupleReaderWriter);
         List<FullTextConfigMetadataEntity> results = new ArrayList<>();
         try {
-            searchIndex(txnId, MetadataPrimaryIndexes.FULL_TEXT_CONFIG_DATASET, searchKey, valueExtractor, results);
+            searchIndex(txnId, mdIndexesProvider.getFullTextConfigEntity().getIndex(), searchKey, valueExtractor,
+                    results);
         } catch (HyracksDataException e) {
             throw new AlgebricksException(e);
         }
@@ -1069,7 +1080,8 @@
                 new MetadataEntityValueExtractor<>(tupleReaderWriter);
         List<FullTextFilterMetadataEntity> results = new ArrayList<>();
         try {
-            searchIndex(txnId, MetadataPrimaryIndexes.FULL_TEXT_FILTER_DATASET, searchKey, valueExtractor, results);
+            searchIndex(txnId, mdIndexesProvider.getFullTextFilterEntity().getIndex(), searchKey, valueExtractor,
+                    results);
         } catch (HyracksDataException e) {
             throw new AlgebricksException(e);
         }
@@ -1083,7 +1095,7 @@
             DatasetTupleTranslator tupleReaderWriter = tupleTranslatorProvider.getDatasetTupleTranslator(false);
             List<Dataset> results = new ArrayList<>();
             IValueExtractor<Dataset> valueExtractor = new MetadataEntityValueExtractor<>(tupleReaderWriter);
-            searchIndex(txnId, MetadataPrimaryIndexes.DATASET_DATASET, searchKey, valueExtractor, results);
+            searchIndex(txnId, mdIndexesProvider.getDatasetEntity().getIndex(), searchKey, valueExtractor, results);
             if (results.isEmpty()) {
                 return null;
             }
@@ -1098,7 +1110,7 @@
             DatasetTupleTranslator tupleReaderWriter = tupleTranslatorProvider.getDatasetTupleTranslator(false);
             IValueExtractor<Dataset> valueExtractor = new MetadataEntityValueExtractor<>(tupleReaderWriter);
             List<Dataset> results = new ArrayList<>();
-            searchIndex(txnId, MetadataPrimaryIndexes.DATASET_DATASET, null, valueExtractor, results);
+            searchIndex(txnId, mdIndexesProvider.getDatasetEntity().getIndex(), null, valueExtractor, results);
             return results;
         } catch (HyracksDataException e) {
             throw new AlgebricksException(e);
@@ -1115,7 +1127,7 @@
                     tupleTranslatorProvider.getDataTypeTupleTranslator(txnId, this, false);
             IValueExtractor<Datatype> valueExtractor = new MetadataEntityValueExtractor<>(tupleReaderWriter);
             List<Datatype> results = new ArrayList<>();
-            searchIndex(txnId, MetadataPrimaryIndexes.DATATYPE_DATASET, null, valueExtractor, results);
+            searchIndex(txnId, mdIndexesProvider.getDatatypeEntity().getIndex(), null, valueExtractor, results);
             return results;
         } catch (HyracksDataException e) {
             throw new AlgebricksException(e);
@@ -1128,7 +1140,8 @@
                     tupleTranslatorProvider.getAdapterTupleTranslator(false);
             List<DatasourceAdapter> results = new ArrayList<>();
             IValueExtractor<DatasourceAdapter> valueExtractor = new MetadataEntityValueExtractor<>(tupleReaderWriter);
-            searchIndex(txnId, MetadataPrimaryIndexes.DATASOURCE_ADAPTER_DATASET, null, valueExtractor, results);
+            searchIndex(txnId, mdIndexesProvider.getDatasourceAdapterEntity().getIndex(), null, valueExtractor,
+                    results);
             return results;
         } catch (HyracksDataException e) {
             throw new AlgebricksException(e);
@@ -1141,7 +1154,7 @@
                     tupleTranslatorProvider.getFeedConnectionTupleTranslator(false);
             List<FeedConnection> results = new ArrayList<>();
             IValueExtractor<FeedConnection> valueExtractor = new MetadataEntityValueExtractor<>(tupleReaderWriter);
-            searchIndex(txnId, MetadataPrimaryIndexes.FEED_CONNECTION_DATASET, null, valueExtractor, results);
+            searchIndex(txnId, mdIndexesProvider.getFeedConnectionEntity().getIndex(), null, valueExtractor, results);
             return results;
         } catch (HyracksDataException e) {
             throw new AlgebricksException(e);
@@ -1542,7 +1555,7 @@
                     tupleTranslatorProvider.getIndexTupleTranslator(txnId, this, false);
             IValueExtractor<Index> valueExtractor = new MetadataEntityValueExtractor<>(tupleReaderWriter);
             List<Index> results = new ArrayList<>();
-            searchIndex(txnId, MetadataPrimaryIndexes.INDEX_DATASET, searchKey, valueExtractor, results);
+            searchIndex(txnId, mdIndexesProvider.getIndexEntity().getIndex(), searchKey, valueExtractor, results);
             if (results.isEmpty()) {
                 return null;
             }
@@ -1561,7 +1574,7 @@
                     tupleTranslatorProvider.getIndexTupleTranslator(txnId, this, false);
             IValueExtractor<Index> valueExtractor = new MetadataEntityValueExtractor<>(tupleReaderWriter);
             List<Index> results = new ArrayList<>();
-            searchIndex(txnId, MetadataPrimaryIndexes.INDEX_DATASET, searchKey, valueExtractor, results);
+            searchIndex(txnId, mdIndexesProvider.getIndexEntity().getIndex(), searchKey, valueExtractor, results);
             return results;
         } catch (HyracksDataException e) {
             throw new AlgebricksException(e);
@@ -1577,7 +1590,7 @@
                     tupleTranslatorProvider.getDataTypeTupleTranslator(txnId, this, false);
             IValueExtractor<Datatype> valueExtractor = new MetadataEntityValueExtractor<>(tupleReaderWriter);
             List<Datatype> results = new ArrayList<>();
-            searchIndex(txnId, MetadataPrimaryIndexes.DATATYPE_DATASET, searchKey, valueExtractor, results);
+            searchIndex(txnId, mdIndexesProvider.getDatatypeEntity().getIndex(), searchKey, valueExtractor, results);
             if (results.isEmpty()) {
                 return null;
             }
@@ -1594,7 +1607,7 @@
             NodeGroupTupleTranslator tupleReaderWriter = tupleTranslatorProvider.getNodeGroupTupleTranslator(false);
             IValueExtractor<NodeGroup> valueExtractor = new MetadataEntityValueExtractor<>(tupleReaderWriter);
             List<NodeGroup> results = new ArrayList<>();
-            searchIndex(txnId, MetadataPrimaryIndexes.NODEGROUP_DATASET, searchKey, valueExtractor, results);
+            searchIndex(txnId, mdIndexesProvider.getNodeGroupEntity().getIndex(), searchKey, valueExtractor, results);
             if (results.isEmpty()) {
                 return null;
             }
@@ -1622,7 +1635,7 @@
                     tupleTranslatorProvider.getFunctionTupleTranslator(txnId, this, false);
             List<Function> results = new ArrayList<>();
             IValueExtractor<Function> valueExtractor = new MetadataEntityValueExtractor<>(tupleReaderWriter);
-            searchIndex(txnId, MetadataPrimaryIndexes.FUNCTION_DATASET, searchKey, valueExtractor, results);
+            searchIndex(txnId, mdIndexesProvider.getFunctionEntity().getIndex(), searchKey, valueExtractor, results);
             return results;
         } catch (HyracksDataException e) {
             throw new AlgebricksException(e);
@@ -1645,8 +1658,8 @@
                     Integer.toString(functionSignature.getArity()));
             // Searches the index for the tuple to be deleted. Acquires an S lock on the 'function' dataset.
             ITupleReference functionTuple =
-                    getTupleToBeDeleted(txnId, MetadataPrimaryIndexes.FUNCTION_DATASET, searchKey);
-            deleteTupleFromIndex(txnId, MetadataPrimaryIndexes.FUNCTION_DATASET, functionTuple);
+                    getTupleToBeDeleted(txnId, mdIndexesProvider.getFunctionEntity().getIndex(), searchKey);
+            deleteTupleFromIndex(txnId, mdIndexesProvider.getFunctionEntity().getIndex(), functionTuple);
         } catch (HyracksDataException e) {
             if (e.matches(ErrorCode.UPDATE_OR_DELETE_NON_EXISTENT_KEY)) {
                 throw new AsterixException(org.apache.asterix.common.exceptions.ErrorCode.UNKNOWN_FUNCTION, e,
@@ -1675,7 +1688,7 @@
         StringBuilder sb = new StringBuilder();
         try {
             RangePredicate rangePred;
-            IMetadataIndex index = MetadataPrimaryIndexes.DATAVERSE_DATASET;
+            IMetadataIndex index = mdIndexesProvider.getDataverseEntity().getIndex();
             String resourceName = index.getFile().toString();
             IIndex indexInstance = datasetLifecycleManager.get(resourceName);
             datasetLifecycleManager.open(resourceName);
@@ -1806,7 +1819,7 @@
     public void initializeDatasetIdFactory(TxnId txnId) throws AlgebricksException {
         int mostRecentDatasetId;
         try {
-            String resourceName = MetadataPrimaryIndexes.DATASET_DATASET.getFile().getRelativePath();
+            String resourceName = mdIndexesProvider.getDatasetEntity().getIndex().getFile().getRelativePath();
             IIndex indexInstance = datasetLifecycleManager.get(resourceName);
             datasetLifecycleManager.open(resourceName);
             try {
@@ -1894,7 +1907,7 @@
             DatasourceAdapterTupleTranslator tupleReaderWriter =
                     tupleTranslatorProvider.getAdapterTupleTranslator(true);
             ITupleReference adapterTuple = tupleReaderWriter.getTupleFromMetadataEntity(adapter);
-            insertTupleIntoIndex(txnId, MetadataPrimaryIndexes.DATASOURCE_ADAPTER_DATASET, adapterTuple);
+            insertTupleIntoIndex(txnId, mdIndexesProvider.getDatasourceAdapterEntity().getIndex(), adapterTuple);
         } catch (HyracksDataException e) {
             if (e.matches(ErrorCode.DUPLICATE_KEY)) {
                 throw new AsterixException(org.apache.asterix.common.exceptions.ErrorCode.ADAPTER_EXISTS, e,
@@ -1913,8 +1926,8 @@
             // Searches the index for the tuple to be deleted. Acquires an S
             // lock on the 'Adapter' dataset.
             ITupleReference datasetTuple =
-                    getTupleToBeDeleted(txnId, MetadataPrimaryIndexes.DATASOURCE_ADAPTER_DATASET, searchKey);
-            deleteTupleFromIndex(txnId, MetadataPrimaryIndexes.DATASOURCE_ADAPTER_DATASET, datasetTuple);
+                    getTupleToBeDeleted(txnId, mdIndexesProvider.getDatasourceAdapterEntity().getIndex(), searchKey);
+            deleteTupleFromIndex(txnId, mdIndexesProvider.getDatasourceAdapterEntity().getIndex(), datasetTuple);
         } catch (HyracksDataException e) {
             if (e.matches(ErrorCode.UPDATE_OR_DELETE_NON_EXISTENT_KEY)) {
                 throw new AsterixException(org.apache.asterix.common.exceptions.ErrorCode.UNKNOWN_ADAPTER, e,
@@ -1934,7 +1947,8 @@
                     tupleTranslatorProvider.getAdapterTupleTranslator(false);
             List<DatasourceAdapter> results = new ArrayList<>();
             IValueExtractor<DatasourceAdapter> valueExtractor = new MetadataEntityValueExtractor<>(tupleReaderWriter);
-            searchIndex(txnId, MetadataPrimaryIndexes.DATASOURCE_ADAPTER_DATASET, searchKey, valueExtractor, results);
+            searchIndex(txnId, mdIndexesProvider.getDatasourceAdapterEntity().getIndex(), searchKey, valueExtractor,
+                    results);
             if (results.isEmpty()) {
                 return null;
             }
@@ -1951,7 +1965,8 @@
             CompactionPolicyTupleTranslator tupleReaderWriter =
                     tupleTranslatorProvider.getCompactionPolicyTupleTranslator(true);
             ITupleReference compactionPolicyTuple = tupleReaderWriter.getTupleFromMetadataEntity(compactionPolicy);
-            insertTupleIntoIndex(txnId, MetadataPrimaryIndexes.COMPACTION_POLICY_DATASET, compactionPolicyTuple);
+            insertTupleIntoIndex(txnId, mdIndexesProvider.getCompactionPolicyEntity().getIndex(),
+                    compactionPolicyTuple);
         } catch (HyracksDataException e) {
             if (e.matches(ErrorCode.DUPLICATE_KEY)) {
                 throw new AsterixException(org.apache.asterix.common.exceptions.ErrorCode.COMPACTION_POLICY_EXISTS, e,
@@ -1971,7 +1986,8 @@
                     tupleTranslatorProvider.getCompactionPolicyTupleTranslator(false);
             List<CompactionPolicy> results = new ArrayList<>();
             IValueExtractor<CompactionPolicy> valueExtractor = new MetadataEntityValueExtractor<>(tupleReaderWriter);
-            searchIndex(txnId, MetadataPrimaryIndexes.COMPACTION_POLICY_DATASET, searchKey, valueExtractor, results);
+            searchIndex(txnId, mdIndexesProvider.getCompactionPolicyEntity().getIndex(), searchKey, valueExtractor,
+                    results);
             if (!results.isEmpty()) {
                 return results.get(0);
             }
@@ -1990,7 +2006,8 @@
                     tupleTranslatorProvider.getAdapterTupleTranslator(false);
             IValueExtractor<DatasourceAdapter> valueExtractor = new MetadataEntityValueExtractor<>(tupleReaderWriter);
             List<DatasourceAdapter> results = new ArrayList<>();
-            searchIndex(txnId, MetadataPrimaryIndexes.DATASOURCE_ADAPTER_DATASET, searchKey, valueExtractor, results);
+            searchIndex(txnId, mdIndexesProvider.getDatasourceAdapterEntity().getIndex(), searchKey, valueExtractor,
+                    results);
             return results;
         } catch (HyracksDataException e) {
             throw new AlgebricksException(e);
@@ -2003,7 +2020,7 @@
             // Insert into the 'Library' dataset.
             LibraryTupleTranslator tupleReaderWriter = tupleTranslatorProvider.getLibraryTupleTranslator(true);
             ITupleReference libraryTuple = tupleReaderWriter.getTupleFromMetadataEntity(library);
-            insertTupleIntoIndex(txnId, MetadataPrimaryIndexes.LIBRARY_DATASET, libraryTuple);
+            insertTupleIntoIndex(txnId, mdIndexesProvider.getLibraryEntity().getIndex(), libraryTuple);
         } catch (HyracksDataException e) {
             if (e.matches(ErrorCode.DUPLICATE_KEY)) {
                 throw new AsterixException(org.apache.asterix.common.exceptions.ErrorCode.LIBRARY_EXISTS, e,
@@ -2029,8 +2046,8 @@
             ITupleReference searchKey = createTuple(dataverseName, libraryName);
             // Searches the index for the tuple to be deleted. Acquires an S lock on the 'Library' dataset.
             ITupleReference datasetTuple =
-                    getTupleToBeDeleted(txnId, MetadataPrimaryIndexes.LIBRARY_DATASET, searchKey);
-            deleteTupleFromIndex(txnId, MetadataPrimaryIndexes.LIBRARY_DATASET, datasetTuple);
+                    getTupleToBeDeleted(txnId, mdIndexesProvider.getLibraryEntity().getIndex(), searchKey);
+            deleteTupleFromIndex(txnId, mdIndexesProvider.getLibraryEntity().getIndex(), datasetTuple);
         } catch (HyracksDataException e) {
             if (e.matches(ErrorCode.UPDATE_OR_DELETE_NON_EXISTENT_KEY)) {
                 throw new AsterixException(org.apache.asterix.common.exceptions.ErrorCode.UNKNOWN_LIBRARY, e,
@@ -2048,7 +2065,7 @@
             LibraryTupleTranslator tupleReaderWriter = tupleTranslatorProvider.getLibraryTupleTranslator(false);
             List<Library> results = new ArrayList<>();
             IValueExtractor<Library> valueExtractor = new MetadataEntityValueExtractor<>(tupleReaderWriter);
-            searchIndex(txnId, MetadataPrimaryIndexes.LIBRARY_DATASET, searchKey, valueExtractor, results);
+            searchIndex(txnId, mdIndexesProvider.getLibraryEntity().getIndex(), searchKey, valueExtractor, results);
             if (results.isEmpty()) {
                 return null;
             }
@@ -2069,7 +2086,7 @@
             // Insert into the 'FeedPolicy' dataset.
             FeedPolicyTupleTranslator tupleReaderWriter = tupleTranslatorProvider.getFeedPolicyTupleTranslator(true);
             ITupleReference feedPolicyTuple = tupleReaderWriter.getTupleFromMetadataEntity(feedPolicy);
-            insertTupleIntoIndex(txnId, MetadataPrimaryIndexes.FEED_POLICY_DATASET, feedPolicyTuple);
+            insertTupleIntoIndex(txnId, mdIndexesProvider.getFeedPolicyEntity().getIndex(), feedPolicyTuple);
         } catch (HyracksDataException e) {
             if (e.matches(ErrorCode.DUPLICATE_KEY)) {
                 throw new AsterixException(org.apache.asterix.common.exceptions.ErrorCode.FEED_POLICY_EXISTS, e,
@@ -2088,7 +2105,7 @@
             FeedPolicyTupleTranslator tupleReaderWriter = tupleTranslatorProvider.getFeedPolicyTupleTranslator(false);
             List<FeedPolicyEntity> results = new ArrayList<>();
             IValueExtractor<FeedPolicyEntity> valueExtractor = new MetadataEntityValueExtractor<>(tupleReaderWriter);
-            searchIndex(txnId, MetadataPrimaryIndexes.FEED_POLICY_DATASET, searchKey, valueExtractor, results);
+            searchIndex(txnId, mdIndexesProvider.getFeedPolicyEntity().getIndex(), searchKey, valueExtractor, results);
             if (!results.isEmpty()) {
                 return results.get(0);
             }
@@ -2104,7 +2121,7 @@
             FeedConnectionTupleTranslator tupleReaderWriter =
                     tupleTranslatorProvider.getFeedConnectionTupleTranslator(true);
             ITupleReference feedConnTuple = tupleReaderWriter.getTupleFromMetadataEntity(feedConnection);
-            insertTupleIntoIndex(txnId, MetadataPrimaryIndexes.FEED_CONNECTION_DATASET, feedConnTuple);
+            insertTupleIntoIndex(txnId, mdIndexesProvider.getFeedConnectionEntity().getIndex(), feedConnTuple);
         } catch (HyracksDataException e) {
             if (e.matches(ErrorCode.DUPLICATE_KEY)) {
                 throw new AsterixException(org.apache.asterix.common.exceptions.ErrorCode.FEED_CONNECTION_EXISTS, e,
@@ -2124,7 +2141,8 @@
                     tupleTranslatorProvider.getFeedConnectionTupleTranslator(false);
             List<FeedConnection> results = new ArrayList<>();
             IValueExtractor<FeedConnection> valueExtractor = new MetadataEntityValueExtractor<>(tupleReaderWriter);
-            searchIndex(txnId, MetadataPrimaryIndexes.FEED_CONNECTION_DATASET, searchKey, valueExtractor, results);
+            searchIndex(txnId, mdIndexesProvider.getFeedConnectionEntity().getIndex(), searchKey, valueExtractor,
+                    results);
             return results;
         } catch (HyracksDataException e) {
             throw new AlgebricksException(e);
@@ -2140,7 +2158,8 @@
                     tupleTranslatorProvider.getFeedConnectionTupleTranslator(false);
             List<FeedConnection> results = new ArrayList<>();
             IValueExtractor<FeedConnection> valueExtractor = new MetadataEntityValueExtractor<>(tupleReaderWriter);
-            searchIndex(txnId, MetadataPrimaryIndexes.FEED_CONNECTION_DATASET, searchKey, valueExtractor, results);
+            searchIndex(txnId, mdIndexesProvider.getFeedConnectionEntity().getIndex(), searchKey, valueExtractor,
+                    results);
             if (!results.isEmpty()) {
                 return results.get(0);
             }
@@ -2156,8 +2175,8 @@
         try {
             ITupleReference searchKey = createTuple(dataverseName, feedName, datasetName);
             ITupleReference tuple =
-                    getTupleToBeDeleted(txnId, MetadataPrimaryIndexes.FEED_CONNECTION_DATASET, searchKey);
-            deleteTupleFromIndex(txnId, MetadataPrimaryIndexes.FEED_CONNECTION_DATASET, tuple);
+                    getTupleToBeDeleted(txnId, mdIndexesProvider.getFeedConnectionEntity().getIndex(), searchKey);
+            deleteTupleFromIndex(txnId, mdIndexesProvider.getFeedConnectionEntity().getIndex(), tuple);
         } catch (HyracksDataException e) {
             if (e.matches(ErrorCode.UPDATE_OR_DELETE_NON_EXISTENT_KEY)) {
                 throw new AsterixException(org.apache.asterix.common.exceptions.ErrorCode.UNKNOWN_FEED_CONNECTION, e,
@@ -2174,7 +2193,7 @@
             // Insert into the 'Feed' dataset.
             FeedTupleTranslator tupleReaderWriter = tupleTranslatorProvider.getFeedTupleTranslator(true);
             ITupleReference feedTuple = tupleReaderWriter.getTupleFromMetadataEntity(feed);
-            insertTupleIntoIndex(txnId, MetadataPrimaryIndexes.FEED_DATASET, feedTuple);
+            insertTupleIntoIndex(txnId, mdIndexesProvider.getFeedEntity().getIndex(), feedTuple);
         } catch (HyracksDataException e) {
             if (e.matches(ErrorCode.DUPLICATE_KEY)) {
                 throw new AsterixException(org.apache.asterix.common.exceptions.ErrorCode.FEED_EXISTS, e,
@@ -2192,7 +2211,7 @@
             FeedTupleTranslator tupleReaderWriter = tupleTranslatorProvider.getFeedTupleTranslator(false);
             List<Feed> results = new ArrayList<>();
             IValueExtractor<Feed> valueExtractor = new MetadataEntityValueExtractor<>(tupleReaderWriter);
-            searchIndex(txnId, MetadataPrimaryIndexes.FEED_DATASET, searchKey, valueExtractor, results);
+            searchIndex(txnId, mdIndexesProvider.getFeedEntity().getIndex(), searchKey, valueExtractor, results);
             if (!results.isEmpty()) {
                 return results.get(0);
             }
@@ -2209,7 +2228,7 @@
             FeedTupleTranslator tupleReaderWriter = tupleTranslatorProvider.getFeedTupleTranslator(false);
             List<Feed> results = new ArrayList<>();
             IValueExtractor<Feed> valueExtractor = new MetadataEntityValueExtractor<>(tupleReaderWriter);
-            searchIndex(txnId, MetadataPrimaryIndexes.FEED_DATASET, searchKey, valueExtractor, results);
+            searchIndex(txnId, mdIndexesProvider.getFeedEntity().getIndex(), searchKey, valueExtractor, results);
             return results;
         } catch (HyracksDataException e) {
             throw new AlgebricksException(e);
@@ -2222,8 +2241,8 @@
             ITupleReference searchKey = createTuple(dataverseName, feedName);
             // Searches the index for the tuple to be deleted. Acquires an S
             // lock on the 'nodegroup' dataset.
-            ITupleReference tuple = getTupleToBeDeleted(txnId, MetadataPrimaryIndexes.FEED_DATASET, searchKey);
-            deleteTupleFromIndex(txnId, MetadataPrimaryIndexes.FEED_DATASET, tuple);
+            ITupleReference tuple = getTupleToBeDeleted(txnId, mdIndexesProvider.getFeedEntity().getIndex(), searchKey);
+            deleteTupleFromIndex(txnId, mdIndexesProvider.getFeedEntity().getIndex(), tuple);
         } catch (HyracksDataException e) {
             if (e.matches(ErrorCode.UPDATE_OR_DELETE_NON_EXISTENT_KEY)) {
                 throw new AsterixException(org.apache.asterix.common.exceptions.ErrorCode.UNKNOWN_FEED, e, feedName);
@@ -2237,8 +2256,9 @@
     public void dropFeedPolicy(TxnId txnId, DataverseName dataverseName, String policyName) throws AlgebricksException {
         try {
             ITupleReference searchKey = createTuple(dataverseName, policyName);
-            ITupleReference tuple = getTupleToBeDeleted(txnId, MetadataPrimaryIndexes.FEED_POLICY_DATASET, searchKey);
-            deleteTupleFromIndex(txnId, MetadataPrimaryIndexes.FEED_POLICY_DATASET, tuple);
+            ITupleReference tuple =
+                    getTupleToBeDeleted(txnId, mdIndexesProvider.getFeedPolicyEntity().getIndex(), searchKey);
+            deleteTupleFromIndex(txnId, mdIndexesProvider.getFeedPolicyEntity().getIndex(), tuple);
         } catch (HyracksDataException e) {
             if (e.matches(ErrorCode.UPDATE_OR_DELETE_NON_EXISTENT_KEY)) {
                 throw new AsterixException(org.apache.asterix.common.exceptions.ErrorCode.UNKNOWN_FEED_POLICY, e,
@@ -2257,7 +2277,7 @@
             FeedPolicyTupleTranslator tupleReaderWriter = tupleTranslatorProvider.getFeedPolicyTupleTranslator(false);
             IValueExtractor<FeedPolicyEntity> valueExtractor = new MetadataEntityValueExtractor<>(tupleReaderWriter);
             List<FeedPolicyEntity> results = new ArrayList<>();
-            searchIndex(txnId, MetadataPrimaryIndexes.FEED_POLICY_DATASET, searchKey, valueExtractor, results);
+            searchIndex(txnId, mdIndexesProvider.getFeedPolicyEntity().getIndex(), searchKey, valueExtractor, results);
             return results;
         } catch (HyracksDataException e) {
             throw new AlgebricksException(e);
@@ -2271,7 +2291,7 @@
             ExternalFileTupleTranslator tupleReaderWriter =
                     tupleTranslatorProvider.getExternalFileTupleTranslator(true);
             ITupleReference externalFileTuple = tupleReaderWriter.getTupleFromMetadataEntity(externalFile);
-            insertTupleIntoIndex(txnId, MetadataPrimaryIndexes.EXTERNAL_FILE_DATASET, externalFileTuple);
+            insertTupleIntoIndex(txnId, mdIndexesProvider.getExternalFileEntity().getIndex(), externalFileTuple);
         } catch (HyracksDataException e) {
             if (e.matches(ErrorCode.DUPLICATE_KEY)) {
                 throw new AsterixException(org.apache.asterix.common.exceptions.ErrorCode.EXTERNAL_FILE_EXISTS, e,
@@ -2290,7 +2310,8 @@
                     tupleTranslatorProvider.getExternalFileTupleTranslator(false);
             IValueExtractor<ExternalFile> valueExtractor = new MetadataEntityValueExtractor<>(tupleReaderWriter);
             List<ExternalFile> results = new ArrayList<>();
-            searchIndex(txnId, MetadataPrimaryIndexes.EXTERNAL_FILE_DATASET, searchKey, valueExtractor, results);
+            searchIndex(txnId, mdIndexesProvider.getExternalFileEntity().getIndex(), searchKey, valueExtractor,
+                    results);
             return results;
         } catch (HyracksDataException e) {
             throw new AlgebricksException(e);
@@ -2306,8 +2327,8 @@
             // Searches the index for the tuple to be deleted. Acquires an S
             // lock on the 'ExternalFile' dataset.
             ITupleReference datasetTuple =
-                    getTupleToBeDeleted(txnId, MetadataPrimaryIndexes.EXTERNAL_FILE_DATASET, searchKey);
-            deleteTupleFromIndex(txnId, MetadataPrimaryIndexes.EXTERNAL_FILE_DATASET, datasetTuple);
+                    getTupleToBeDeleted(txnId, mdIndexesProvider.getExternalFileEntity().getIndex(), searchKey);
+            deleteTupleFromIndex(txnId, mdIndexesProvider.getExternalFileEntity().getIndex(), datasetTuple);
         } catch (HyracksDataException e) {
             if (e.matches(ErrorCode.UPDATE_OR_DELETE_NON_EXISTENT_KEY)) {
                 throw new AsterixException(org.apache.asterix.common.exceptions.ErrorCode.UNKNOWN_EXTERNAL_FILE, e,
@@ -2368,7 +2389,8 @@
                     tupleTranslatorProvider.getExternalFileTupleTranslator(false);
             IValueExtractor<ExternalFile> valueExtractor = new MetadataEntityValueExtractor<>(tupleReaderWriter);
             List<ExternalFile> results = new ArrayList<>();
-            searchIndex(txnId, MetadataPrimaryIndexes.EXTERNAL_FILE_DATASET, searchKey, valueExtractor, results);
+            searchIndex(txnId, mdIndexesProvider.getExternalFileEntity().getIndex(), searchKey, valueExtractor,
+                    results);
             if (results.isEmpty()) {
                 return null;
             }
@@ -2384,7 +2406,7 @@
             // Insert into the 'Synonym' dataset.
             SynonymTupleTranslator tupleReaderWriter = tupleTranslatorProvider.getSynonymTupleTranslator(true);
             ITupleReference synonymTuple = tupleReaderWriter.getTupleFromMetadataEntity(synonym);
-            insertTupleIntoIndex(txnId, MetadataPrimaryIndexes.SYNONYM_DATASET, synonymTuple);
+            insertTupleIntoIndex(txnId, mdIndexesProvider.getSynonymEntity().getIndex(), synonymTuple);
         } catch (HyracksDataException e) {
             if (e.matches(ErrorCode.DUPLICATE_KEY)) {
                 throw new AsterixException(org.apache.asterix.common.exceptions.ErrorCode.SYNONYM_EXISTS, e,
@@ -2412,8 +2434,8 @@
             // Searches the index for the tuple to be deleted. Acquires an S
             // lock on the 'Synonym' dataset.
             ITupleReference synonymTuple =
-                    getTupleToBeDeleted(txnId, MetadataPrimaryIndexes.SYNONYM_DATASET, searchKey);
-            deleteTupleFromIndex(txnId, MetadataPrimaryIndexes.SYNONYM_DATASET, synonymTuple);
+                    getTupleToBeDeleted(txnId, mdIndexesProvider.getSynonymEntity().getIndex(), searchKey);
+            deleteTupleFromIndex(txnId, mdIndexesProvider.getSynonymEntity().getIndex(), synonymTuple);
         } catch (HyracksDataException e) {
             if (e.matches(ErrorCode.UPDATE_OR_DELETE_NON_EXISTENT_KEY)) {
                 throw new AsterixException(org.apache.asterix.common.exceptions.ErrorCode.UNKNOWN_SYNONYM, e,
@@ -2447,7 +2469,7 @@
             SynonymTupleTranslator tupleReaderWriter = tupleTranslatorProvider.getSynonymTupleTranslator(false);
             List<Synonym> results = new ArrayList<>();
             IValueExtractor<Synonym> valueExtractor = new MetadataEntityValueExtractor<>(tupleReaderWriter);
-            searchIndex(txnId, MetadataPrimaryIndexes.SYNONYM_DATASET, searchKey, valueExtractor, results);
+            searchIndex(txnId, mdIndexesProvider.getSynonymEntity().getIndex(), searchKey, valueExtractor, results);
             if (results.isEmpty()) {
                 return null;
             }
@@ -2464,7 +2486,7 @@
             SynonymTupleTranslator tupleReaderWriter = tupleTranslatorProvider.getSynonymTupleTranslator(false);
             IValueExtractor<Synonym> valueExtractor = new MetadataEntityValueExtractor<>(tupleReaderWriter);
             List<Synonym> results = new ArrayList<>();
-            searchIndex(txnId, MetadataPrimaryIndexes.SYNONYM_DATASET, searchKey, valueExtractor, results);
+            searchIndex(txnId, mdIndexesProvider.getSynonymEntity().getIndex(), searchKey, valueExtractor, results);
             return results;
         } catch (HyracksDataException e) {
             throw new AlgebricksException(e);
@@ -2479,12 +2501,12 @@
             ITupleReference searchKey = createTuple(dataset.getDataverseName(), dataset.getDatasetName());
             // Searches the index for the tuple to be deleted. Acquires an S lock on the 'dataset' dataset.
             ITupleReference datasetTuple =
-                    getTupleToBeDeleted(txnId, MetadataPrimaryIndexes.DATASET_DATASET, searchKey);
-            deleteTupleFromIndex(txnId, MetadataPrimaryIndexes.DATASET_DATASET, datasetTuple);
+                    getTupleToBeDeleted(txnId, mdIndexesProvider.getDatasetEntity().getIndex(), searchKey);
+            deleteTupleFromIndex(txnId, mdIndexesProvider.getDatasetEntity().getIndex(), datasetTuple);
             // Insert into the 'dataset' dataset.
             DatasetTupleTranslator tupleReaderWriter = tupleTranslatorProvider.getDatasetTupleTranslator(true);
             datasetTuple = tupleReaderWriter.getTupleFromMetadataEntity(dataset);
-            insertTupleIntoIndex(txnId, MetadataPrimaryIndexes.DATASET_DATASET, datasetTuple);
+            insertTupleIntoIndex(txnId, mdIndexesProvider.getDatasetEntity().getIndex(), datasetTuple);
         } catch (HyracksDataException e) {
             if (e.matches(ErrorCode.UPDATE_OR_DELETE_NON_EXISTENT_KEY)) {
                 throw new AsterixException(org.apache.asterix.common.exceptions.ErrorCode.UNKNOWN_DATASET_IN_DATAVERSE,
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/api/IMetadataExtension.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/api/IMetadataExtension.java
index fe7e441..8831214 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/api/IMetadataExtension.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/api/IMetadataExtension.java
@@ -26,6 +26,7 @@
 import org.apache.asterix.common.api.IExtension;
 import org.apache.asterix.common.dataflow.ICcApplicationContext;
 import org.apache.asterix.common.exceptions.ACIDException;
+import org.apache.asterix.metadata.bootstrap.MetadataIndexesProvider;
 import org.apache.asterix.metadata.entitytupletranslators.MetadataTupleTranslatorProvider;
 import org.apache.hyracks.algebricks.core.algebra.metadata.IMetadataProvider;
 import org.apache.hyracks.api.application.INCServiceContext;
@@ -45,13 +46,15 @@
      * @return The tuple translator provider that must be used by the {@code IMetadataNode } to read and write core
      *         {@code IMetadataEntity} objects
      */
-    MetadataTupleTranslatorProvider getMetadataTupleTranslatorProvider();
+    MetadataTupleTranslatorProvider getMetadataTupleTranslatorProvider(MetadataIndexesProvider metadataIndexesProvider);
+
+    MetadataIndexesProvider getMetadataIndexesProvider(INCServiceContext ncServiceCtx);
 
     /**
      * @return A list of additional extension instances of {@code IMetadataIndex} that are introduced by the extension
      */
     @SuppressWarnings("rawtypes")
-    List<ExtensionMetadataDataset> getExtensionIndexes();
+    List<ExtensionMetadataDataset> getExtensionIndexes(MetadataIndexesProvider metadataIndexesProvider);
 
     /**
      * Called when booting the {@code IMetadataNode}
@@ -60,7 +63,8 @@
      * @throws RemoteException
      * @throws ACIDException
      */
-    void initializeMetadata(INCServiceContext ncServiceCtx) throws HyracksDataException, RemoteException, ACIDException;
+    void initializeMetadata(INCServiceContext ncServiceCtx, MetadataIndexesProvider mdIndexesProvider)
+            throws HyracksDataException, RemoteException, ACIDException;
 
     /**
      * Returns a factory for {@link org.apache.asterix.metadata.declared.MetadataProvider},
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/api/INCExtensionManager.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/api/INCExtensionManager.java
index 18b2ac6..32b25fa 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/api/INCExtensionManager.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/api/INCExtensionManager.java
@@ -18,6 +18,7 @@
  */
 package org.apache.asterix.metadata.api;
 
+import org.apache.asterix.metadata.bootstrap.MetadataIndexesProvider;
 import org.apache.asterix.metadata.entitytupletranslators.MetadataTupleTranslatorProvider;
 
 public interface INCExtensionManager {
@@ -25,4 +26,6 @@
      * @return the metadata tuple translator provider
      */
     MetadataTupleTranslatorProvider getMetadataTupleTranslatorProvider();
+
+    MetadataIndexesProvider getMetadataIndexesProvider();
 }
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/CompactionPolicyEntity.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/CompactionPolicyEntity.java
new file mode 100644
index 0000000..4cfbdff
--- /dev/null
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/CompactionPolicyEntity.java
@@ -0,0 +1,102 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.asterix.metadata.bootstrap;
+
+import static org.apache.asterix.metadata.bootstrap.MetadataPrimaryIndexes.PROPERTIES_COMPACTION_POLICY;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_CLASSNAME;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_COMPACTION_POLICY;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_DATAVERSE_NAME;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.RECORD_NAME_COMPACTION_POLICY;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.asterix.om.types.ARecordType;
+import org.apache.asterix.om.types.BuiltinType;
+import org.apache.asterix.om.types.IAType;
+
+public final class CompactionPolicyEntity {
+
+    private static final CompactionPolicyEntity COMPACTION_POLICY =
+            new CompactionPolicyEntity(new MetadataIndex(PROPERTIES_COMPACTION_POLICY, 3,
+                    new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING },
+                    Arrays.asList(List.of(FIELD_NAME_DATAVERSE_NAME), List.of(FIELD_NAME_COMPACTION_POLICY)), 0,
+                    compactionPolicyType(), true, new int[] { 0, 1 }), 2, -1);
+
+    private final int payloadPosition;
+    private final MetadataIndex index;
+    private final int databaseNameIndex;
+    private final int dataverseNameIndex;
+    private final int policyNameIndex;
+    private final int classNameIndex;
+
+    private CompactionPolicyEntity(MetadataIndex index, int payloadPosition, int startIndex) {
+        this.index = index;
+        this.payloadPosition = payloadPosition;
+        this.databaseNameIndex = startIndex++;
+        this.dataverseNameIndex = startIndex++;
+        this.policyNameIndex = startIndex++;
+        this.classNameIndex = startIndex++;
+    }
+
+    public static CompactionPolicyEntity of(boolean cloudDeployment) {
+        return COMPACTION_POLICY;
+    }
+
+    public MetadataIndex getIndex() {
+        return index;
+    }
+
+    public ARecordType getRecordType() {
+        return index.getPayloadRecordType();
+    }
+
+    public int payloadPosition() {
+        return payloadPosition;
+    }
+
+    public int databaseNameIndex() {
+        return databaseNameIndex;
+    }
+
+    public int dataverseNameIndex() {
+        return dataverseNameIndex;
+    }
+
+    public int policyNameIndex() {
+        return policyNameIndex;
+    }
+
+    public int classNameIndex() {
+        return classNameIndex;
+    }
+
+    private static ARecordType compactionPolicyType() {
+        return MetadataRecordTypes.createRecordType(
+                // RecordTypeName
+                RECORD_NAME_COMPACTION_POLICY,
+                // FieldNames
+                new String[] { FIELD_NAME_DATAVERSE_NAME, FIELD_NAME_COMPACTION_POLICY, FIELD_NAME_CLASSNAME },
+                // FieldTypes
+                new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING, BuiltinType.ASTRING },
+                //IsOpen?
+                true);
+    }
+}
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/DatasetEntity.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/DatasetEntity.java
new file mode 100644
index 0000000..c7928a6
--- /dev/null
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/DatasetEntity.java
@@ -0,0 +1,196 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.asterix.metadata.bootstrap;
+
+import static org.apache.asterix.metadata.bootstrap.MetadataPrimaryIndexes.PROPERTIES_DATASET;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.COMPACTION_POLICY_PROPERTIES_RECORDTYPE;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.DATASET_HINTS_RECORDTYPE;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.EXTERNAL_DETAILS_RECORDTYPE;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_COMPACTION_POLICY;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_COMPACTION_POLICY_PROPERTIES;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_DATASET_ID;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_DATASET_NAME;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_DATASET_TYPE;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_DATATYPE_DATAVERSE_NAME;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_DATATYPE_NAME;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_DATAVERSE_NAME;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_EXTERNAL_DETAILS;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_GROUP_NAME;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_HINTS;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_INTERNAL_DETAILS;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_PENDING_OP;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_TIMESTAMP;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.INTERNAL_DETAILS_RECORDTYPE;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.RECORD_NAME_DATASET;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.asterix.om.types.AOrderedListType;
+import org.apache.asterix.om.types.ARecordType;
+import org.apache.asterix.om.types.AUnionType;
+import org.apache.asterix.om.types.AUnorderedListType;
+import org.apache.asterix.om.types.BuiltinType;
+import org.apache.asterix.om.types.IAType;
+
+public final class DatasetEntity {
+
+    private static final DatasetEntity DATASET = new DatasetEntity(
+            new MetadataIndex(PROPERTIES_DATASET, 3, new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING },
+                    Arrays.asList(List.of(FIELD_NAME_DATAVERSE_NAME), List.of(FIELD_NAME_DATASET_NAME)), 0,
+                    datasetType(), true, new int[] { 0, 1 }),
+            2, -1);
+
+    private final int payloadPosition;
+    private final MetadataIndex index;
+    private final int databaseNameIndex;
+    private final int dataverseNameIndex;
+    private final int datasetNameIndex;
+    private final int datatypeDataverseNameIndex;
+    private final int datatypeNameIndex;
+    private final int datasetTypeIndex;
+    private final int groupNameIndex;
+    private final int compactionPolicyIndex;
+    private final int compactionPolicyPropertiesIndex;
+    private final int internalDetailsIndex;
+    private final int externalDetailsIndex;
+    private final int hintsIndex;
+    private final int timestampIndex;
+    private final int datasetIdIndex;
+    private final int pendingOpIndex;
+
+    private DatasetEntity(MetadataIndex index, int payloadPosition, int startIndex) {
+        this.index = index;
+        this.payloadPosition = payloadPosition;
+        this.databaseNameIndex = startIndex++;
+        this.dataverseNameIndex = startIndex++;
+        this.datasetNameIndex = startIndex++;
+        this.datatypeDataverseNameIndex = startIndex++;
+        this.datatypeNameIndex = startIndex++;
+        this.datasetTypeIndex = startIndex++;
+        this.groupNameIndex = startIndex++;
+        this.compactionPolicyIndex = startIndex++;
+        this.compactionPolicyPropertiesIndex = startIndex++;
+        this.internalDetailsIndex = startIndex++;
+        this.externalDetailsIndex = startIndex++;
+        this.hintsIndex = startIndex++;
+        this.timestampIndex = startIndex++;
+        this.datasetIdIndex = startIndex++;
+        this.pendingOpIndex = startIndex++;
+    }
+
+    public static DatasetEntity of(boolean cloudDeployment) {
+        return DATASET;
+    }
+
+    public MetadataIndex getIndex() {
+        return index;
+    }
+
+    public ARecordType getRecordType() {
+        return index.getPayloadRecordType();
+    }
+
+    public int payloadPosition() {
+        return payloadPosition;
+    }
+
+    public int databaseNameIndex() {
+        return databaseNameIndex;
+    }
+
+    public int dataverseNameIndex() {
+        return dataverseNameIndex;
+    }
+
+    public int datasetNameIndex() {
+        return datasetNameIndex;
+    }
+
+    public int datatypeDataverseNameIndex() {
+        return datatypeDataverseNameIndex;
+    }
+
+    public int datatypeNameIndex() {
+        return datatypeNameIndex;
+    }
+
+    public int datasetTypeIndex() {
+        return datasetTypeIndex;
+    }
+
+    public int groupNameIndex() {
+        return groupNameIndex;
+    }
+
+    public int compactionPolicyIndex() {
+        return compactionPolicyIndex;
+    }
+
+    public int compactionPolicyPropertiesIndex() {
+        return compactionPolicyPropertiesIndex;
+    }
+
+    public int internalDetailsIndex() {
+        return internalDetailsIndex;
+    }
+
+    public int externalDetailsIndex() {
+        return externalDetailsIndex;
+    }
+
+    public int hintsIndex() {
+        return hintsIndex;
+    }
+
+    public int timestampIndex() {
+        return timestampIndex;
+    }
+
+    public int datasetIdIndex() {
+        return datasetIdIndex;
+    }
+
+    public int pendingOpIndex() {
+        return pendingOpIndex;
+    }
+
+    private static ARecordType datasetType() {
+        return MetadataRecordTypes.createRecordType(
+                // RecordTypeName
+                RECORD_NAME_DATASET,
+                // FieldNames
+                new String[] { FIELD_NAME_DATAVERSE_NAME, FIELD_NAME_DATASET_NAME, FIELD_NAME_DATATYPE_DATAVERSE_NAME,
+                        FIELD_NAME_DATATYPE_NAME, FIELD_NAME_DATASET_TYPE, FIELD_NAME_GROUP_NAME,
+                        FIELD_NAME_COMPACTION_POLICY, FIELD_NAME_COMPACTION_POLICY_PROPERTIES,
+                        FIELD_NAME_INTERNAL_DETAILS, FIELD_NAME_EXTERNAL_DETAILS, FIELD_NAME_HINTS,
+                        FIELD_NAME_TIMESTAMP, FIELD_NAME_DATASET_ID, FIELD_NAME_PENDING_OP },
+                // FieldTypes
+                new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING, BuiltinType.ASTRING, BuiltinType.ASTRING,
+                        BuiltinType.ASTRING, BuiltinType.ASTRING, BuiltinType.ASTRING,
+                        new AOrderedListType(COMPACTION_POLICY_PROPERTIES_RECORDTYPE, null),
+                        AUnionType.createUnknownableType(INTERNAL_DETAILS_RECORDTYPE),
+                        AUnionType.createUnknownableType(EXTERNAL_DETAILS_RECORDTYPE),
+                        new AUnorderedListType(DATASET_HINTS_RECORDTYPE, null), BuiltinType.ASTRING, BuiltinType.AINT32,
+                        BuiltinType.AINT32 },
+                //IsOpen?
+                true);
+    }
+}
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/DatasourceAdapterEntity.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/DatasourceAdapterEntity.java
new file mode 100644
index 0000000..41aeee9
--- /dev/null
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/DatasourceAdapterEntity.java
@@ -0,0 +1,118 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.asterix.metadata.bootstrap;
+
+import static org.apache.asterix.metadata.bootstrap.MetadataPrimaryIndexes.PROPERTIES_DATASOURCE_ADAPTER;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_CLASSNAME;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_DATAVERSE_NAME;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_NAME;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_TIMESTAMP;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_TYPE;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.RECORD_NAME_DATASOURCE_ADAPTER;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.asterix.om.types.ARecordType;
+import org.apache.asterix.om.types.BuiltinType;
+import org.apache.asterix.om.types.IAType;
+
+public final class DatasourceAdapterEntity {
+
+    private static final DatasourceAdapterEntity DATASOURCE_ADAPTER =
+            new DatasourceAdapterEntity(new MetadataIndex(PROPERTIES_DATASOURCE_ADAPTER, 3,
+                    new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING },
+                    Arrays.asList(List.of(FIELD_NAME_DATAVERSE_NAME), List.of(FIELD_NAME_NAME)), 0,
+                    datasourceAdapterType(), true, new int[] { 0, 1 }), 2, -1);
+
+    private final int payloadPosition;
+    private final MetadataIndex index;
+    private final int databaseNameIndex;
+    private final int dataverseNameIndex;
+    private final int adapterNameIndex;
+    private final int classNameIndex;
+    private final int typeIndex;
+    private final int timestampIndex;
+
+    private DatasourceAdapterEntity(MetadataIndex index, int payloadPosition, int startIndex) {
+        this.index = index;
+        this.payloadPosition = payloadPosition;
+        this.databaseNameIndex = startIndex++;
+        this.dataverseNameIndex = startIndex++;
+        this.adapterNameIndex = startIndex++;
+        this.classNameIndex = startIndex++;
+        this.typeIndex = startIndex++;
+        this.timestampIndex = startIndex++;
+    }
+
+    public static DatasourceAdapterEntity of(boolean cloudDeployment) {
+        return DATASOURCE_ADAPTER;
+    }
+
+    public MetadataIndex getIndex() {
+        return index;
+    }
+
+    public ARecordType getRecordType() {
+        return index.getPayloadRecordType();
+    }
+
+    public int payloadPosition() {
+        return payloadPosition;
+    }
+
+    public int databaseNameIndex() {
+        return databaseNameIndex;
+    }
+
+    public int dataverseNameIndex() {
+        return dataverseNameIndex;
+    }
+
+    public int adapterNameIndex() {
+        return adapterNameIndex;
+    }
+
+    public int classNameIndex() {
+        return classNameIndex;
+    }
+
+    public int typeIndex() {
+        return typeIndex;
+    }
+
+    public int timestampIndex() {
+        return timestampIndex;
+    }
+
+    private static ARecordType datasourceAdapterType() {
+        return MetadataRecordTypes.createRecordType(
+                // RecordTypeName
+                RECORD_NAME_DATASOURCE_ADAPTER,
+                // FieldNames
+                new String[] { FIELD_NAME_DATAVERSE_NAME, FIELD_NAME_NAME, FIELD_NAME_CLASSNAME, FIELD_NAME_TYPE,
+                        FIELD_NAME_TIMESTAMP },
+                // FieldTypes
+                new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING, BuiltinType.ASTRING, BuiltinType.ASTRING,
+                        BuiltinType.ASTRING },
+                //IsOpen?
+                true);
+    }
+}
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/DatatypeEntity.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/DatatypeEntity.java
new file mode 100644
index 0000000..a26f232
--- /dev/null
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/DatatypeEntity.java
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.asterix.metadata.bootstrap;
+
+import static org.apache.asterix.metadata.bootstrap.MetadataPrimaryIndexes.PROPERTIES_DATATYPE;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.DERIVEDTYPE_RECORDTYPE;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_DATATYPE_NAME;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_DATAVERSE_NAME;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_DERIVED;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_TIMESTAMP;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.RECORD_NAME_DATATYPE;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.asterix.om.types.ARecordType;
+import org.apache.asterix.om.types.AUnionType;
+import org.apache.asterix.om.types.BuiltinType;
+import org.apache.asterix.om.types.IAType;
+
+public final class DatatypeEntity {
+
+    private static final DatatypeEntity DATATYPE = new DatatypeEntity(
+            new MetadataIndex(PROPERTIES_DATATYPE, 3, new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING },
+                    Arrays.asList(List.of(FIELD_NAME_DATAVERSE_NAME), List.of(FIELD_NAME_DATATYPE_NAME)), 0,
+                    datatypeType(), true, new int[] { 0, 1 }),
+            2, -1);
+
+    private final int payloadPosition;
+    private final MetadataIndex index;
+    private final int databaseNameIndex;
+    private final int dataverseNameIndex;
+    private final int datatypeNameIndex;
+    private final int derivedIndex;
+    private final int timestampIndex;
+
+    private DatatypeEntity(MetadataIndex index, int payloadPosition, int startIndex) {
+        this.index = index;
+        this.payloadPosition = payloadPosition;
+        this.databaseNameIndex = startIndex++;
+        this.dataverseNameIndex = startIndex++;
+        this.datatypeNameIndex = startIndex++;
+        this.derivedIndex = startIndex++;
+        this.timestampIndex = startIndex++;
+    }
+
+    public static DatatypeEntity of(boolean cloudDeployment) {
+        return DATATYPE;
+    }
+
+    public MetadataIndex getIndex() {
+        return index;
+    }
+
+    public ARecordType getRecordType() {
+        return index.getPayloadRecordType();
+    }
+
+    public int payloadPosition() {
+        return payloadPosition;
+    }
+
+    public int databaseNameIndex() {
+        return databaseNameIndex;
+    }
+
+    public int dataverseNameIndex() {
+        return dataverseNameIndex;
+    }
+
+    public int datatypeNameIndex() {
+        return datatypeNameIndex;
+    }
+
+    public int derivedIndex() {
+        return derivedIndex;
+    }
+
+    public int timestampIndex() {
+        return timestampIndex;
+    }
+
+    private static ARecordType datatypeType() {
+        return MetadataRecordTypes.createRecordType(
+                // RecordTypeName
+                RECORD_NAME_DATATYPE,
+                // FieldNames
+                new String[] { FIELD_NAME_DATAVERSE_NAME, FIELD_NAME_DATATYPE_NAME, FIELD_NAME_DERIVED,
+                        FIELD_NAME_TIMESTAMP },
+                // FieldTypes
+                new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING,
+                        AUnionType.createUnknownableType(DERIVEDTYPE_RECORDTYPE), BuiltinType.ASTRING },
+                //IsOpen?
+                true);
+    }
+}
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/DataverseEntity.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/DataverseEntity.java
new file mode 100644
index 0000000..8a6cc03
--- /dev/null
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/DataverseEntity.java
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.asterix.metadata.bootstrap;
+
+import static org.apache.asterix.metadata.bootstrap.MetadataPrimaryIndexes.PROPERTIES_DATAVERSE;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_DATAVERSE_NAME;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_DATA_FORMAT;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_PENDING_OP;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_TIMESTAMP;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.RECORD_NAME_DATAVERSE;
+
+import java.util.List;
+
+import org.apache.asterix.om.types.ARecordType;
+import org.apache.asterix.om.types.BuiltinType;
+import org.apache.asterix.om.types.IAType;
+
+public final class DataverseEntity {
+
+    private static final DataverseEntity DATAVERSE =
+            new DataverseEntity(
+                    new MetadataIndex(PROPERTIES_DATAVERSE, 2, new IAType[] { BuiltinType.ASTRING },
+                            List.of(List.of(FIELD_NAME_DATAVERSE_NAME)), 0, dataverseType(), true, new int[] { 0 }),
+                    1, -1);
+
+    private final int payloadPosition;
+    private final MetadataIndex index;
+    private final int databaseNameIndex;
+    private final int dataverseNameIndex;
+    private final int dataFormatIndex;
+    private final int timestampIndex;
+    private final int pendingOpIndex;
+
+    private DataverseEntity(MetadataIndex index, int payloadPosition, int startIndex) {
+        this.index = index;
+        this.payloadPosition = payloadPosition;
+        this.databaseNameIndex = startIndex++;
+        this.dataverseNameIndex = startIndex++;
+        this.dataFormatIndex = startIndex++;
+        this.timestampIndex = startIndex++;
+        this.pendingOpIndex = startIndex++;
+    }
+
+    public static DataverseEntity of(boolean cloudDeployment) {
+        return DATAVERSE;
+    }
+
+    public MetadataIndex getIndex() {
+        return index;
+    }
+
+    public ARecordType getRecordType() {
+        return index.getPayloadRecordType();
+    }
+
+    public int payloadPosition() {
+        return payloadPosition;
+    }
+
+    public int databaseNameIndex() {
+        return databaseNameIndex;
+    }
+
+    public int dataverseNameIndex() {
+        return dataverseNameIndex;
+    }
+
+    public int dataFormatIndex() {
+        return dataFormatIndex;
+    }
+
+    public int timestampIndex() {
+        return timestampIndex;
+    }
+
+    public int pendingOpIndex() {
+        return pendingOpIndex;
+    }
+
+    private static ARecordType dataverseType() {
+        return MetadataRecordTypes.createRecordType(
+                // RecordTypeName
+                RECORD_NAME_DATAVERSE,
+                // FieldNames
+                new String[] { FIELD_NAME_DATAVERSE_NAME, FIELD_NAME_DATA_FORMAT, FIELD_NAME_TIMESTAMP,
+                        FIELD_NAME_PENDING_OP },
+                // FieldTypes
+                new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING, BuiltinType.ASTRING, BuiltinType.AINT32 },
+                //IsOpen?
+                true);
+    }
+}
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/ExternalFileEntity.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/ExternalFileEntity.java
new file mode 100644
index 0000000..2827fd73
--- /dev/null
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/ExternalFileEntity.java
@@ -0,0 +1,134 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.asterix.metadata.bootstrap;
+
+import static org.apache.asterix.metadata.bootstrap.MetadataPrimaryIndexes.PROPERTIES_EXTERNAL_FILE;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_DATASET_NAME;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_DATAVERSE_NAME;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_FILE_MOD_TIME;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_FILE_NAME;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_FILE_NUMBER;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_FILE_SIZE;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_PENDING_OP;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.RECORD_NAME_EXTERNAL_FILE;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.asterix.om.types.ARecordType;
+import org.apache.asterix.om.types.BuiltinType;
+import org.apache.asterix.om.types.IAType;
+
+public final class ExternalFileEntity {
+
+    private static final ExternalFileEntity EXTERNAL_FILE = new ExternalFileEntity(
+            new MetadataIndex(PROPERTIES_EXTERNAL_FILE, 4,
+                    new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING, BuiltinType.AINT32 },
+                    Arrays.asList(List.of(FIELD_NAME_DATAVERSE_NAME), List.of(FIELD_NAME_DATASET_NAME),
+                            List.of(FIELD_NAME_FILE_NUMBER)),
+                    0, externalFileType(), true, new int[] { 0, 1, 2 }),
+            3, -1);
+
+    private final int payloadPosition;
+    private final MetadataIndex index;
+    private final int databaseNameIndex;
+    private final int dataverseNameIndex;
+    private final int datasetNameIndex;
+    private final int fileNumberIndex;
+    private final int fileNameIndex;
+    private final int fileSizeIndex;
+    private final int fileModDateIndex;
+    private final int pendingOpIndex;
+
+    private ExternalFileEntity(MetadataIndex index, int payloadPosition, int startIndex) {
+        this.index = index;
+        this.payloadPosition = payloadPosition;
+        this.databaseNameIndex = startIndex++;
+        this.dataverseNameIndex = startIndex++;
+        this.datasetNameIndex = startIndex++;
+        this.fileNumberIndex = startIndex++;
+        this.fileNameIndex = startIndex++;
+        this.fileSizeIndex = startIndex++;
+        this.fileModDateIndex = startIndex++;
+        this.pendingOpIndex = startIndex++;
+    }
+
+    public static ExternalFileEntity of(boolean cloudDeployment) {
+        return EXTERNAL_FILE;
+    }
+
+    public MetadataIndex getIndex() {
+        return index;
+    }
+
+    public ARecordType getRecordType() {
+        return index.getPayloadRecordType();
+    }
+
+    public int payloadPosition() {
+        return payloadPosition;
+    }
+
+    public int databaseNameIndex() {
+        return databaseNameIndex;
+    }
+
+    public int dataverseNameIndex() {
+        return dataverseNameIndex;
+    }
+
+    public int datasetNameIndex() {
+        return datasetNameIndex;
+    }
+
+    public int fileNumberIndex() {
+        return fileNumberIndex;
+    }
+
+    public int fileNameIndex() {
+        return fileNameIndex;
+    }
+
+    public int fileSizeIndex() {
+        return fileSizeIndex;
+    }
+
+    public int fileModDateIndex() {
+        return fileModDateIndex;
+    }
+
+    public int pendingOpIndex() {
+        return pendingOpIndex;
+    }
+
+    private static ARecordType externalFileType() {
+        return MetadataRecordTypes.createRecordType(
+                // RecordTypeName
+                RECORD_NAME_EXTERNAL_FILE,
+                // FieldNames
+                new String[] { FIELD_NAME_DATAVERSE_NAME, FIELD_NAME_DATASET_NAME, FIELD_NAME_FILE_NUMBER,
+                        FIELD_NAME_FILE_NAME, FIELD_NAME_FILE_SIZE, FIELD_NAME_FILE_MOD_TIME, FIELD_NAME_PENDING_OP },
+                // FieldTypes
+                new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING, BuiltinType.AINT32, BuiltinType.ASTRING,
+                        BuiltinType.AINT64, BuiltinType.ADATETIME, BuiltinType.AINT32 },
+                //IsOpen?
+                true);
+    }
+}
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/FeedConnectionEntity.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/FeedConnectionEntity.java
new file mode 100644
index 0000000..4e4c0d7
--- /dev/null
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/FeedConnectionEntity.java
@@ -0,0 +1,128 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.asterix.metadata.bootstrap;
+
+import static org.apache.asterix.metadata.bootstrap.MetadataPrimaryIndexes.PROPERTIES_FEED_CONNECTION;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_APPLIED_FUNCTIONS;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_DATASET_NAME;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_DATAVERSE_NAME;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_FEED_NAME;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_POLICY_NAME;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_RETURN_TYPE;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.RECORD_NAME_FEED_CONNECTION;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.asterix.om.types.ARecordType;
+import org.apache.asterix.om.types.AUnorderedListType;
+import org.apache.asterix.om.types.BuiltinType;
+import org.apache.asterix.om.types.IAType;
+
+public final class FeedConnectionEntity {
+
+    private static final FeedConnectionEntity FEED_CONNECTION = new FeedConnectionEntity(
+            new MetadataIndex(PROPERTIES_FEED_CONNECTION, 4,
+                    new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING, BuiltinType.ASTRING },
+                    Arrays.asList(List.of(FIELD_NAME_DATAVERSE_NAME), List.of(FIELD_NAME_FEED_NAME),
+                            List.of(FIELD_NAME_DATASET_NAME)),
+                    0, feedConnectionType(), true, new int[] { 0, 1, 2 }),
+            3, -1);
+
+    private final int payloadPosition;
+    private final MetadataIndex index;
+    private final int databaseNameIndex;
+    private final int dataverseNameIndex;
+    private final int feedNameIndex;
+    private final int datasetNameIndex;
+    private final int outputTypeIndex;
+    private final int appliedFunctionsIndex;
+    private final int policyIndex;
+
+    private FeedConnectionEntity(MetadataIndex index, int payloadPosition, int startIndex) {
+        this.index = index;
+        this.payloadPosition = payloadPosition;
+        this.databaseNameIndex = startIndex++;
+        this.dataverseNameIndex = startIndex++;
+        this.feedNameIndex = startIndex++;
+        this.datasetNameIndex = startIndex++;
+        this.outputTypeIndex = startIndex++;
+        this.appliedFunctionsIndex = startIndex++;
+        this.policyIndex = startIndex++;
+    }
+
+    public static FeedConnectionEntity of(boolean cloudDeployment) {
+        return FEED_CONNECTION;
+    }
+
+    public MetadataIndex getIndex() {
+        return index;
+    }
+
+    public ARecordType getRecordType() {
+        return index.getPayloadRecordType();
+    }
+
+    public int payloadPosition() {
+        return payloadPosition;
+    }
+
+    public int databaseNameIndex() {
+        return databaseNameIndex;
+    }
+
+    public int dataverseNameIndex() {
+        return dataverseNameIndex;
+    }
+
+    public int feedNameIndex() {
+        return feedNameIndex;
+    }
+
+    public int datasetNameIndex() {
+        return datasetNameIndex;
+    }
+
+    public int outputTypeIndex() {
+        return outputTypeIndex;
+    }
+
+    public int appliedFunctionsIndex() {
+        return appliedFunctionsIndex;
+    }
+
+    public int policyIndex() {
+        return policyIndex;
+    }
+
+    private static ARecordType feedConnectionType() {
+        return MetadataRecordTypes.createRecordType(
+                // RecordTypeName
+                RECORD_NAME_FEED_CONNECTION,
+                // FieldNames
+                new String[] { FIELD_NAME_DATAVERSE_NAME, FIELD_NAME_FEED_NAME, FIELD_NAME_DATASET_NAME,
+                        FIELD_NAME_RETURN_TYPE, FIELD_NAME_APPLIED_FUNCTIONS, FIELD_NAME_POLICY_NAME },
+                // FieldTypes
+                new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING, BuiltinType.ASTRING, BuiltinType.ASTRING,
+                        new AUnorderedListType(BuiltinType.ASTRING, null), BuiltinType.ASTRING },
+                //IsOpen?
+                true);
+    }
+}
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/FeedEntity.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/FeedEntity.java
new file mode 100644
index 0000000..1270fb1
--- /dev/null
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/FeedEntity.java
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.asterix.metadata.bootstrap;
+
+import static org.apache.asterix.metadata.bootstrap.MetadataPrimaryIndexes.PROPERTIES_FEED;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FEED_ADAPTER_CONFIGURATION_RECORDTYPE;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_ADAPTER_CONFIGURATION;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_DATAVERSE_NAME;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_FEED_NAME;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_TIMESTAMP;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.RECORD_NAME_FEED;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.asterix.om.types.ARecordType;
+import org.apache.asterix.om.types.AUnorderedListType;
+import org.apache.asterix.om.types.BuiltinType;
+import org.apache.asterix.om.types.IAType;
+
+public final class FeedEntity {
+
+    private static final FeedEntity FEED = new FeedEntity(
+            new MetadataIndex(PROPERTIES_FEED, 3, new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING },
+                    Arrays.asList(List.of(FIELD_NAME_DATAVERSE_NAME), List.of(FIELD_NAME_FEED_NAME)), 0, feedType(),
+                    true, new int[] { 0, 1 }),
+            2, -1);
+
+    private final int payloadPosition;
+    private final MetadataIndex index;
+    private final int databaseNameIndex;
+    private final int dataverseNameIndex;
+    private final int feedNameIndex;
+    private final int adapterConfigIndex;
+    private final int timestampIndex;
+
+    private FeedEntity(MetadataIndex index, int payloadPosition, int startIndex) {
+        this.index = index;
+        this.payloadPosition = payloadPosition;
+        this.databaseNameIndex = startIndex++;
+        this.dataverseNameIndex = startIndex++;
+        this.feedNameIndex = startIndex++;
+        this.adapterConfigIndex = startIndex++;
+        this.timestampIndex = startIndex++;
+    }
+
+    public static FeedEntity of(boolean cloudDeployment) {
+        return FEED;
+    }
+
+    public MetadataIndex getIndex() {
+        return index;
+    }
+
+    public ARecordType getRecordType() {
+        return index.getPayloadRecordType();
+    }
+
+    public int payloadPosition() {
+        return payloadPosition;
+    }
+
+    public int databaseNameIndex() {
+        return databaseNameIndex;
+    }
+
+    public int dataverseNameIndex() {
+        return dataverseNameIndex;
+    }
+
+    public int feedNameIndex() {
+        return feedNameIndex;
+    }
+
+    public int adapterConfigIndex() {
+        return adapterConfigIndex;
+    }
+
+    public int timestampIndex() {
+        return timestampIndex;
+    }
+
+    private static ARecordType feedType() {
+        return MetadataRecordTypes.createRecordType(
+                // RecordTypeName
+                RECORD_NAME_FEED,
+                // FieldNames
+                new String[] { FIELD_NAME_DATAVERSE_NAME, FIELD_NAME_FEED_NAME, FIELD_NAME_ADAPTER_CONFIGURATION,
+                        FIELD_NAME_TIMESTAMP },
+                // FieldTypes
+                new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING,
+                        new AUnorderedListType(FEED_ADAPTER_CONFIGURATION_RECORDTYPE, null), BuiltinType.ASTRING },
+                //IsOpen?
+                true);
+    }
+}
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/FeedPolicyEntity.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/FeedPolicyEntity.java
new file mode 100644
index 0000000..2d952e6
--- /dev/null
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/FeedPolicyEntity.java
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.asterix.metadata.bootstrap;
+
+import static org.apache.asterix.metadata.bootstrap.MetadataPrimaryIndexes.PROPERTIES_FEED_POLICY;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_DATAVERSE_NAME;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_DESCRIPTION;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_POLICY_NAME;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_PROPERTIES;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.POLICY_PARAMS_RECORDTYPE;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.RECORD_NAME_FEED_POLICY;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.asterix.om.types.ARecordType;
+import org.apache.asterix.om.types.AUnorderedListType;
+import org.apache.asterix.om.types.BuiltinType;
+import org.apache.asterix.om.types.IAType;
+
+public final class FeedPolicyEntity {
+
+    private static final FeedPolicyEntity FEED_POLICY = new FeedPolicyEntity(
+            new MetadataIndex(PROPERTIES_FEED_POLICY, 3, new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING },
+                    Arrays.asList(List.of(FIELD_NAME_DATAVERSE_NAME), List.of(FIELD_NAME_POLICY_NAME)), 0,
+                    feedPolicyType(), true, new int[] { 0, 1 }),
+            2, -1);
+
+    private final int payloadPosition;
+    private final MetadataIndex index;
+    private final int databaseNameIndex;
+    private final int dataverseNameIndex;
+    private final int policyNameIndex;
+    private final int descriptionIndex;
+    private final int propertiesIndex;
+
+    private FeedPolicyEntity(MetadataIndex index, int payloadPosition, int startIndex) {
+        this.index = index;
+        this.payloadPosition = payloadPosition;
+        this.databaseNameIndex = startIndex++;
+        this.dataverseNameIndex = startIndex++;
+        this.policyNameIndex = startIndex++;
+        this.descriptionIndex = startIndex++;
+        this.propertiesIndex = startIndex++;
+    }
+
+    public static FeedPolicyEntity of(boolean cloudDeployment) {
+        return FEED_POLICY;
+    }
+
+    public MetadataIndex getIndex() {
+        return index;
+    }
+
+    public ARecordType getRecordType() {
+        return index.getPayloadRecordType();
+    }
+
+    public int payloadPosition() {
+        return payloadPosition;
+    }
+
+    public int databaseNameIndex() {
+        return databaseNameIndex;
+    }
+
+    public int dataverseNameIndex() {
+        return dataverseNameIndex;
+    }
+
+    public int policyNameIndex() {
+        return policyNameIndex;
+    }
+
+    public int descriptionIndex() {
+        return descriptionIndex;
+    }
+
+    public int propertiesIndex() {
+        return propertiesIndex;
+    }
+
+    private static ARecordType feedPolicyType() {
+        return MetadataRecordTypes.createRecordType(
+                // RecordTypeName
+                RECORD_NAME_FEED_POLICY,
+                // FieldNames
+                new String[] { FIELD_NAME_DATAVERSE_NAME, FIELD_NAME_POLICY_NAME, FIELD_NAME_DESCRIPTION,
+                        FIELD_NAME_PROPERTIES },
+                // FieldTypes
+                new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING, BuiltinType.ASTRING,
+                        new AUnorderedListType(POLICY_PARAMS_RECORDTYPE, null) },
+                //IsOpen?
+                true);
+    }
+}
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/FullTextConfigEntity.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/FullTextConfigEntity.java
new file mode 100644
index 0000000..1c97822
--- /dev/null
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/FullTextConfigEntity.java
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.asterix.metadata.bootstrap;
+
+import static org.apache.asterix.metadata.bootstrap.MetadataPrimaryIndexes.PROPERTIES_FULL_TEXT_CONFIG;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_DATAVERSE_NAME;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_FULL_TEXT_CONFIG_NAME;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_FULL_TEXT_FILTER_PIPELINE;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_FULL_TEXT_TOKENIZER;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.RECORD_NAME_FULL_TEXT_CONFIG;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.asterix.om.types.AOrderedListType;
+import org.apache.asterix.om.types.ARecordType;
+import org.apache.asterix.om.types.AUnionType;
+import org.apache.asterix.om.types.BuiltinType;
+import org.apache.asterix.om.types.IAType;
+
+public final class FullTextConfigEntity {
+
+    private static final FullTextConfigEntity FULL_TEXT_CONFIG = new FullTextConfigEntity(
+            new MetadataIndex(PROPERTIES_FULL_TEXT_CONFIG, 3, new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING },
+                    Arrays.asList(List.of(FIELD_NAME_DATAVERSE_NAME), List.of(FIELD_NAME_FULL_TEXT_CONFIG_NAME)), 0,
+                    fullTextConfigType(), true, new int[] { 0, 1 }),
+            2, -1);
+
+    private final int payloadPosition;
+    private final MetadataIndex index;
+    private final int databaseNameIndex;
+    private final int dataverseNameIndex;
+    private final int configNameIndex;
+    private final int tokenizerIndex;
+    private final int filterPipelineIndex;
+
+    private FullTextConfigEntity(MetadataIndex index, int payloadPosition, int startIndex) {
+        this.index = index;
+        this.payloadPosition = payloadPosition;
+        this.databaseNameIndex = startIndex++;
+        this.dataverseNameIndex = startIndex++;
+        this.configNameIndex = startIndex++;
+        this.tokenizerIndex = startIndex++;
+        this.filterPipelineIndex = startIndex++;;
+    }
+
+    public static FullTextConfigEntity of(boolean cloudDeployment) {
+        return FULL_TEXT_CONFIG;
+    }
+
+    public MetadataIndex getIndex() {
+        return index;
+    }
+
+    public ARecordType getRecordType() {
+        return index.getPayloadRecordType();
+    }
+
+    public int payloadPosition() {
+        return payloadPosition;
+    }
+
+    public int databaseNameIndex() {
+        return databaseNameIndex;
+    }
+
+    public int dataverseNameIndex() {
+        return dataverseNameIndex;
+    }
+
+    public int configNameIndex() {
+        return configNameIndex;
+    }
+
+    public int tokenizerIndex() {
+        return tokenizerIndex;
+    }
+
+    public int filterPipelineIndex() {
+        return filterPipelineIndex;
+    }
+
+    private static ARecordType fullTextConfigType() {
+        return MetadataRecordTypes
+                .createRecordType(RECORD_NAME_FULL_TEXT_CONFIG,
+                        new String[] { FIELD_NAME_DATAVERSE_NAME, FIELD_NAME_FULL_TEXT_CONFIG_NAME,
+                                FIELD_NAME_FULL_TEXT_TOKENIZER, FIELD_NAME_FULL_TEXT_FILTER_PIPELINE },
+                        new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING,
+                                AUnionType.createNullableType(BuiltinType.ASTRING), AUnionType.createNullableType(
+                                        new AOrderedListType(BuiltinType.ASTRING, "FullTextFilterPipeline")) },
+                        true);
+    }
+}
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/FullTextFilterEntity.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/FullTextFilterEntity.java
new file mode 100644
index 0000000..aefb5a1
--- /dev/null
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/FullTextFilterEntity.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.asterix.metadata.bootstrap;
+
+import static org.apache.asterix.metadata.bootstrap.MetadataPrimaryIndexes.PROPERTIES_FULL_TEXT_FILTER;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_DATAVERSE_NAME;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_FULL_TEXT_FILTER_NAME;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_FULL_TEXT_FILTER_TYPE;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.RECORD_NAME_FULL_TEXT_FILTER;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.asterix.om.types.ARecordType;
+import org.apache.asterix.om.types.BuiltinType;
+import org.apache.asterix.om.types.IAType;
+
+public final class FullTextFilterEntity {
+
+    private static final FullTextFilterEntity FULL_TEXT_CONFIG = new FullTextFilterEntity(
+            new MetadataIndex(PROPERTIES_FULL_TEXT_FILTER, 3, new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING },
+                    Arrays.asList(List.of(FIELD_NAME_DATAVERSE_NAME), List.of(FIELD_NAME_FULL_TEXT_FILTER_NAME)), 0,
+                    fullTextFilterType(), true, new int[] { 0, 1 }),
+            2, -1);
+
+    private final int payloadPosition;
+    private final MetadataIndex index;
+    private final int databaseNameIndex;
+    private final int dataverseNameIndex;
+    private final int filterNameIndex;
+    private final int filterTypeIndex;
+
+    private FullTextFilterEntity(MetadataIndex index, int payloadPosition, int startIndex) {
+        this.index = index;
+        this.payloadPosition = payloadPosition;
+        this.databaseNameIndex = startIndex++;
+        this.dataverseNameIndex = startIndex++;
+        this.filterNameIndex = startIndex++;
+        this.filterTypeIndex = startIndex++;
+    }
+
+    public static FullTextFilterEntity of(boolean cloudDeployment) {
+        return FULL_TEXT_CONFIG;
+    }
+
+    public MetadataIndex getIndex() {
+        return index;
+    }
+
+    public ARecordType getRecordType() {
+        return index.getPayloadRecordType();
+    }
+
+    public int payloadPosition() {
+        return payloadPosition;
+    }
+
+    public int databaseNameIndex() {
+        return databaseNameIndex;
+    }
+
+    public int dataverseNameIndex() {
+        return dataverseNameIndex;
+    }
+
+    public int filterNameIndex() {
+        return filterNameIndex;
+    }
+
+    public int filterTypeIndex() {
+        return filterTypeIndex;
+    }
+
+    private static ARecordType fullTextFilterType() {
+        return MetadataRecordTypes.createRecordType(RECORD_NAME_FULL_TEXT_FILTER,
+                new String[] { FIELD_NAME_DATAVERSE_NAME, FIELD_NAME_FULL_TEXT_FILTER_NAME,
+                        FIELD_NAME_FULL_TEXT_FILTER_TYPE },
+                new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING, BuiltinType.ASTRING }, true);
+    }
+}
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/FunctionEntity.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/FunctionEntity.java
new file mode 100644
index 0000000..a180796
--- /dev/null
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/FunctionEntity.java
@@ -0,0 +1,150 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.asterix.metadata.bootstrap;
+
+import static org.apache.asterix.metadata.bootstrap.MetadataPrimaryIndexes.PROPERTIES_FUNCTION;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_ARITY;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_DATAVERSE_NAME;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_DEFINITION;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_DEPENDENCIES;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_KIND;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_LANGUAGE;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_NAME;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_PARAMS;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_RETURN_TYPE;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.RECORD_NAME_FUNCTION;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.asterix.om.types.AOrderedListType;
+import org.apache.asterix.om.types.ARecordType;
+import org.apache.asterix.om.types.BuiltinType;
+import org.apache.asterix.om.types.IAType;
+
+public final class FunctionEntity {
+
+    private static final FunctionEntity FUNCTION = new FunctionEntity(new MetadataIndex(PROPERTIES_FUNCTION, 4,
+            new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING, BuiltinType.ASTRING },
+            Arrays.asList(List.of(FIELD_NAME_DATAVERSE_NAME), List.of(FIELD_NAME_NAME), List.of(FIELD_NAME_ARITY)), 0,
+            functionType(), true, new int[] { 0, 1, 2 }), 3, -1);
+
+    private final int payloadPosition;
+    private final MetadataIndex index;
+    private final int databaseNameIndex;
+    private final int dataverseNameIndex;
+    private final int functionNameIndex;
+    private final int functionArityIndex;
+    private final int functionParamListIndex;
+    private final int functionReturnTypeIndex;
+    private final int functionDefinitionIndex;
+    private final int functionLanguageIndex;
+    private final int functionKindIndex;
+    private final int functionDependenciesIndex;
+
+    private FunctionEntity(MetadataIndex index, int payloadPosition, int startIndex) {
+        this.index = index;
+        this.payloadPosition = payloadPosition;
+        this.databaseNameIndex = startIndex++;
+        this.dataverseNameIndex = startIndex++;
+        this.functionNameIndex = startIndex++;
+        this.functionArityIndex = startIndex++;
+        this.functionParamListIndex = startIndex++;
+        this.functionReturnTypeIndex = startIndex++;
+        this.functionDefinitionIndex = startIndex++;
+        this.functionLanguageIndex = startIndex++;
+        this.functionKindIndex = startIndex++;
+        this.functionDependenciesIndex = startIndex++;
+    }
+
+    public static FunctionEntity of(boolean cloudDeployment) {
+        return FUNCTION;
+    }
+
+    public MetadataIndex getIndex() {
+        return index;
+    }
+
+    public ARecordType getRecordType() {
+        return index.getPayloadRecordType();
+    }
+
+    public int payloadPosition() {
+        return payloadPosition;
+    }
+
+    public int databaseNameIndex() {
+        return databaseNameIndex;
+    }
+
+    public int dataverseNameIndex() {
+        return dataverseNameIndex;
+    }
+
+    public int functionNameIndex() {
+        return functionNameIndex;
+    }
+
+    public int functionArityIndex() {
+        return functionArityIndex;
+    }
+
+    public int functionParamListIndex() {
+        return functionParamListIndex;
+    }
+
+    public int functionReturnTypeIndex() {
+        return functionReturnTypeIndex;
+    }
+
+    public int functionLanguageIndex() {
+        return functionLanguageIndex;
+    }
+
+    public int functionDefinitionIndex() {
+        return functionDefinitionIndex;
+    }
+
+    public int functionKindIndex() {
+        return functionKindIndex;
+    }
+
+    public int functionDependenciesIndex() {
+        return functionDependenciesIndex;
+    }
+
+    private static ARecordType functionType() {
+        return MetadataRecordTypes.createRecordType(
+                // RecordTypeName
+                RECORD_NAME_FUNCTION,
+                // FieldNames
+                new String[] { FIELD_NAME_DATAVERSE_NAME, FIELD_NAME_NAME, FIELD_NAME_ARITY, FIELD_NAME_PARAMS,
+                        FIELD_NAME_RETURN_TYPE, FIELD_NAME_DEFINITION, FIELD_NAME_LANGUAGE, FIELD_NAME_KIND,
+                        FIELD_NAME_DEPENDENCIES },
+                // FieldTypes
+                new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING, BuiltinType.ASTRING,
+                        new AOrderedListType(BuiltinType.ASTRING, null), BuiltinType.ASTRING, BuiltinType.ASTRING,
+                        BuiltinType.ASTRING, BuiltinType.ASTRING,
+                        new AOrderedListType(
+                                new AOrderedListType(new AOrderedListType(BuiltinType.ASTRING, null), null), null) },
+                //IsOpen?
+                true);
+    }
+}
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/IndexEntity.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/IndexEntity.java
new file mode 100644
index 0000000..95ba52f
--- /dev/null
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/IndexEntity.java
@@ -0,0 +1,145 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.asterix.metadata.bootstrap;
+
+import static org.apache.asterix.metadata.bootstrap.MetadataPrimaryIndexes.PROPERTIES_INDEX;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_DATASET_NAME;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_DATAVERSE_NAME;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_INDEX_NAME;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_INDEX_STRUCTURE;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_IS_PRIMARY;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_PENDING_OP;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_SEARCH_KEY;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_TIMESTAMP;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.RECORD_NAME_INDEX;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.asterix.om.types.AOrderedListType;
+import org.apache.asterix.om.types.ARecordType;
+import org.apache.asterix.om.types.BuiltinType;
+import org.apache.asterix.om.types.IAType;
+
+public final class IndexEntity {
+
+    private static final IndexEntity INDEX =
+            new IndexEntity(
+                    new MetadataIndex(PROPERTIES_INDEX, 4,
+                            new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING, BuiltinType.ASTRING },
+                            Arrays.asList(List.of(FIELD_NAME_DATAVERSE_NAME), List.of(FIELD_NAME_DATASET_NAME),
+                                    List.of(FIELD_NAME_INDEX_NAME)),
+                            0, indexType(), true, new int[] { 0, 1, 2 }),
+                    3, -1);
+
+    private final int payloadPosition;
+    private final MetadataIndex index;
+    private final int databaseNameIndex;
+    private final int dataverseNameIndex;
+    private final int datasetNameIndex;
+    private final int indexNameIndex;
+    private final int indexStructureIndex;
+    private final int searchKeyIndex;
+    private final int isPrimaryIndex;
+    private final int timestampIndex;
+    private final int pendingOpIndex;
+
+    private IndexEntity(MetadataIndex index, int payloadPosition, int startIndex) {
+        this.index = index;
+        this.payloadPosition = payloadPosition;
+        this.databaseNameIndex = startIndex++;
+        this.dataverseNameIndex = startIndex++;
+        this.datasetNameIndex = startIndex++;
+        this.indexNameIndex = startIndex++;
+        this.indexStructureIndex = startIndex++;
+        this.searchKeyIndex = startIndex++;
+        this.isPrimaryIndex = startIndex++;
+        this.timestampIndex = startIndex++;
+        this.pendingOpIndex = startIndex++;
+    }
+
+    public static IndexEntity of(boolean cloudDeployment) {
+        return INDEX;
+    }
+
+    public MetadataIndex getIndex() {
+        return index;
+    }
+
+    public ARecordType getRecordType() {
+        return index.getPayloadRecordType();
+    }
+
+    public int payloadPosition() {
+        return payloadPosition;
+    }
+
+    public int databaseNameIndex() {
+        return databaseNameIndex;
+    }
+
+    public int dataverseNameIndex() {
+        return dataverseNameIndex;
+    }
+
+    public int datasetNameIndex() {
+        return datasetNameIndex;
+    }
+
+    public int indexNameIndex() {
+        return indexNameIndex;
+    }
+
+    public int indexStructureIndex() {
+        return indexStructureIndex;
+    }
+
+    public int searchKeyIndex() {
+        return searchKeyIndex;
+    }
+
+    public int isPrimaryIndex() {
+        return isPrimaryIndex;
+    }
+
+    public int timestampIndex() {
+        return timestampIndex;
+    }
+
+    public int pendingOpIndex() {
+        return pendingOpIndex;
+    }
+
+    private static ARecordType indexType() {
+        return MetadataRecordTypes.createRecordType(
+                // RecordTypeName
+                RECORD_NAME_INDEX,
+                // FieldNames
+                new String[] { FIELD_NAME_DATAVERSE_NAME, FIELD_NAME_DATASET_NAME, FIELD_NAME_INDEX_NAME,
+                        FIELD_NAME_INDEX_STRUCTURE, FIELD_NAME_SEARCH_KEY, FIELD_NAME_IS_PRIMARY, FIELD_NAME_TIMESTAMP,
+                        FIELD_NAME_PENDING_OP },
+                // FieldTypes
+                new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING, BuiltinType.ASTRING, BuiltinType.ASTRING,
+                        new AOrderedListType(new AOrderedListType(BuiltinType.ASTRING, null), null),
+                        BuiltinType.ABOOLEAN, BuiltinType.ASTRING, BuiltinType.AINT32 },
+                //IsOpen?
+                true);
+    }
+}
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/LibraryEntity.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/LibraryEntity.java
new file mode 100644
index 0000000..1d99ead
--- /dev/null
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/LibraryEntity.java
@@ -0,0 +1,102 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.asterix.metadata.bootstrap;
+
+import static org.apache.asterix.metadata.bootstrap.MetadataPrimaryIndexes.PROPERTIES_LIBRARY;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_DATAVERSE_NAME;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_NAME;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_TIMESTAMP;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.RECORD_NAME_LIBRARY;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.asterix.om.types.ARecordType;
+import org.apache.asterix.om.types.BuiltinType;
+import org.apache.asterix.om.types.IAType;
+
+public final class LibraryEntity {
+
+    private static final LibraryEntity LIBRARY = new LibraryEntity(
+            new MetadataIndex(PROPERTIES_LIBRARY, 3, new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING },
+                    Arrays.asList(List.of(FIELD_NAME_DATAVERSE_NAME), List.of(FIELD_NAME_NAME)), 0, libraryType(), true,
+                    new int[] { 0, 1 }),
+            2, -1);
+
+    private final int payloadPosition;
+    private final MetadataIndex index;
+    private final int databaseNameIndex;
+    private final int dataverseNameIndex;
+    private final int libraryNameIndex;
+    private final int timestampIndex;
+
+    private LibraryEntity(MetadataIndex index, int payloadPosition, int startIndex) {
+        this.index = index;
+        this.payloadPosition = payloadPosition;
+        this.databaseNameIndex = startIndex++;
+        this.dataverseNameIndex = startIndex++;
+        this.libraryNameIndex = startIndex++;
+        this.timestampIndex = startIndex++;
+    }
+
+    public static LibraryEntity of(boolean cloudDeployment) {
+        return LIBRARY;
+    }
+
+    public MetadataIndex getIndex() {
+        return index;
+    }
+
+    public ARecordType getRecordType() {
+        return index.getPayloadRecordType();
+    }
+
+    public int payloadPosition() {
+        return payloadPosition;
+    }
+
+    public int databaseNameIndex() {
+        return databaseNameIndex;
+    }
+
+    public int dataverseNameIndex() {
+        return dataverseNameIndex;
+    }
+
+    public int libraryNameIndex() {
+        return libraryNameIndex;
+    }
+
+    public int timestampIndex() {
+        return timestampIndex;
+    }
+
+    private static ARecordType libraryType() {
+        return MetadataRecordTypes.createRecordType(
+                // RecordTypeName
+                RECORD_NAME_LIBRARY,
+                // FieldNames
+                new String[] { FIELD_NAME_DATAVERSE_NAME, FIELD_NAME_NAME, FIELD_NAME_TIMESTAMP },
+                // FieldTypes
+                new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING, BuiltinType.ASTRING },
+                //IsOpen?
+                true);
+    }
+}
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/MetadataBootstrap.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/MetadataBootstrap.java
index 014bc5c..514dda4 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/MetadataBootstrap.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/MetadataBootstrap.java
@@ -71,7 +71,6 @@
 import org.apache.asterix.om.types.BuiltinType;
 import org.apache.asterix.om.types.BuiltinTypeMap;
 import org.apache.asterix.om.types.IAType;
-import org.apache.asterix.runtime.formats.NonTaggedDataFormat;
 import org.apache.asterix.transaction.management.opcallbacks.PrimaryIndexOperationTrackerFactory;
 import org.apache.asterix.transaction.management.opcallbacks.SecondaryIndexOperationTrackerFactory;
 import org.apache.asterix.transaction.management.resource.DatasetLocalResourceFactory;
@@ -119,16 +118,7 @@
     private static String metadataNodeName;
     private static List<String> nodeNames;
     private static boolean isNewUniverse;
-    private static final IMetadataIndex[] PRIMARY_INDEXES =
-            new IMetadataIndex[] { MetadataPrimaryIndexes.DATAVERSE_DATASET, MetadataPrimaryIndexes.DATASET_DATASET,
-                    MetadataPrimaryIndexes.DATATYPE_DATASET, MetadataPrimaryIndexes.INDEX_DATASET,
-                    MetadataPrimaryIndexes.NODE_DATASET, MetadataPrimaryIndexes.NODEGROUP_DATASET,
-                    MetadataPrimaryIndexes.FUNCTION_DATASET, MetadataPrimaryIndexes.DATASOURCE_ADAPTER_DATASET,
-                    MetadataPrimaryIndexes.FEED_DATASET, MetadataPrimaryIndexes.FEED_POLICY_DATASET,
-                    MetadataPrimaryIndexes.LIBRARY_DATASET, MetadataPrimaryIndexes.COMPACTION_POLICY_DATASET,
-                    MetadataPrimaryIndexes.EXTERNAL_FILE_DATASET, MetadataPrimaryIndexes.FEED_CONNECTION_DATASET,
-                    MetadataPrimaryIndexes.SYNONYM_DATASET, MetadataPrimaryIndexes.FULL_TEXT_CONFIG_DATASET,
-                    MetadataPrimaryIndexes.FULL_TEXT_FILTER_DATASET };
+    private static IMetadataIndex[] PRIMARY_INDEXES;
 
     private MetadataBootstrap() {
     }
@@ -138,13 +128,15 @@
      *
      * @param ncServiceContext
      * @param isNewUniverse
+     * @param mdIndexesProvider
      * @throws ACIDException
      * @throws RemoteException
      * @throws AlgebricksException
      * @throws Exception
      */
-    public static void startUniverse(INCServiceContext ncServiceContext, boolean isNewUniverse)
-            throws RemoteException, ACIDException, AlgebricksException {
+    public static void startUniverse(INCServiceContext ncServiceContext, boolean isNewUniverse,
+            MetadataIndexesProvider mdIndexesProvider) throws RemoteException, ACIDException, AlgebricksException {
+        PRIMARY_INDEXES = mdIndexesProvider.getMetadataIndexes();
         MetadataBootstrap.setNewUniverse(isNewUniverse);
         appContext = (INcApplicationContext) ncServiceContext.getApplicationContext();
 
@@ -157,7 +149,7 @@
         MetadataTransactionContext mdTxnCtx = MetadataManager.INSTANCE.beginTransaction();
         try {
             for (int i = 0; i < PRIMARY_INDEXES.length; i++) {
-                enlistMetadataDataset(ncServiceContext, PRIMARY_INDEXES[i]);
+                enlistMetadataDataset(ncServiceContext, PRIMARY_INDEXES[i], mdIndexesProvider);
             }
             if (LOGGER.isInfoEnabled()) {
                 LOGGER.info(
@@ -177,8 +169,8 @@
                 }
             } else {
                 insertNewCompactionPoliciesIfNotExist(mdTxnCtx);
-                insertSynonymEntitiesIfNotExist(mdTxnCtx);
-                insertFullTextConfigAndFilterIfNotExist(mdTxnCtx);
+                insertSynonymEntitiesIfNotExist(mdTxnCtx, mdIndexesProvider);
+                insertFullTextConfigAndFilterIfNotExist(mdTxnCtx, mdIndexesProvider);
             }
             // #. initialize datasetIdFactory
             MetadataManager.INSTANCE.initializeDatasetIdFactory(mdTxnCtx);
@@ -199,9 +191,7 @@
     }
 
     private static void insertInitialDataverses(MetadataTransactionContext mdTxnCtx) throws AlgebricksException {
-        String dataFormat = NonTaggedDataFormat.NON_TAGGED_DATA_FORMAT;
-        MetadataManager.INSTANCE.addDataverse(mdTxnCtx,
-                new Dataverse(MetadataConstants.METADATA_DATAVERSE_NAME, dataFormat, MetadataUtil.PENDING_NO_OP));
+        MetadataManager.INSTANCE.addDataverse(mdTxnCtx, MetadataBuiltinEntities.METADATA_DATAVERSE);
         MetadataManager.INSTANCE.addDataverse(mdTxnCtx, MetadataBuiltinEntities.DEFAULT_DATAVERSE);
     }
 
@@ -306,9 +296,9 @@
         }
     }
 
-    private static void insertSynonymEntitiesIfNotExist(MetadataTransactionContext mdTxnCtx)
-            throws AlgebricksException {
-        IAType synonymDatasetRecordType = MetadataPrimaryIndexes.SYNONYM_DATASET.getPayloadRecordType();
+    private static void insertSynonymEntitiesIfNotExist(MetadataTransactionContext mdTxnCtx,
+            MetadataIndexesProvider mdIndexesProvider) throws AlgebricksException {
+        IAType synonymDatasetRecordType = mdIndexesProvider.getSynonymEntity().getRecordType();
         if (MetadataManager.INSTANCE.getDatatype(mdTxnCtx, MetadataConstants.METADATA_DATAVERSE_NAME,
                 synonymDatasetRecordType.getTypeName()) == null) {
             MetadataManager.INSTANCE.addDatatype(mdTxnCtx, new Datatype(MetadataConstants.METADATA_DATAVERSE_NAME,
@@ -316,7 +306,7 @@
         }
         if (MetadataManager.INSTANCE.getDataset(mdTxnCtx, MetadataConstants.METADATA_DATAVERSE_NAME,
                 MetadataConstants.SYNONYM_DATASET_NAME) == null) {
-            insertMetadataDatasets(mdTxnCtx, new IMetadataIndex[] { MetadataPrimaryIndexes.SYNONYM_DATASET });
+            insertMetadataDatasets(mdTxnCtx, new IMetadataIndex[] { mdIndexesProvider.getSynonymEntity().getIndex() });
         }
     }
 
@@ -324,18 +314,18 @@
     // 1) may not have such a full-text config dataset in the metadata catalog,
     // 2) may not have the default full-text config as an entry in the metadata catalog
     // So here, let's try to insert if not exists
-    private static void insertFullTextConfigAndFilterIfNotExist(MetadataTransactionContext mdTxnCtx)
-            throws AlgebricksException {
+    private static void insertFullTextConfigAndFilterIfNotExist(MetadataTransactionContext mdTxnCtx,
+            MetadataIndexesProvider metadataIndexesProvider) throws AlgebricksException {
 
         // We need to insert data types first because datasets depend on data types
         // ToDo: create a new function to reduce duplicated code here: addDatatypeIfNotExist()
-        IAType fullTextConfigRecordType = MetadataPrimaryIndexes.FULL_TEXT_CONFIG_DATASET.getPayloadRecordType();
+        IAType fullTextConfigRecordType = metadataIndexesProvider.getFullTextConfigEntity().getRecordType();
         if (MetadataManager.INSTANCE.getDatatype(mdTxnCtx, MetadataConstants.METADATA_DATAVERSE_NAME,
                 fullTextConfigRecordType.getTypeName()) == null) {
             MetadataManager.INSTANCE.addDatatype(mdTxnCtx, new Datatype(MetadataConstants.METADATA_DATAVERSE_NAME,
                     fullTextConfigRecordType.getTypeName(), fullTextConfigRecordType, false));
         }
-        IAType fullTextFilterRecordType = MetadataPrimaryIndexes.FULL_TEXT_FILTER_DATASET.getPayloadRecordType();
+        IAType fullTextFilterRecordType = metadataIndexesProvider.getFullTextFilterEntity().getRecordType();
         if (MetadataManager.INSTANCE.getDatatype(mdTxnCtx, MetadataConstants.METADATA_DATAVERSE_NAME,
                 fullTextFilterRecordType.getTypeName()) == null) {
             MetadataManager.INSTANCE.addDatatype(mdTxnCtx, new Datatype(MetadataConstants.METADATA_DATAVERSE_NAME,
@@ -344,11 +334,13 @@
 
         if (MetadataManager.INSTANCE.getDataset(mdTxnCtx, MetadataConstants.METADATA_DATAVERSE_NAME,
                 MetadataConstants.FULL_TEXT_CONFIG_DATASET_NAME) == null) {
-            insertMetadataDatasets(mdTxnCtx, new IMetadataIndex[] { MetadataPrimaryIndexes.FULL_TEXT_CONFIG_DATASET });
+            insertMetadataDatasets(mdTxnCtx,
+                    new IMetadataIndex[] { metadataIndexesProvider.getFullTextConfigEntity().getIndex() });
         }
         if (MetadataManager.INSTANCE.getDataset(mdTxnCtx, MetadataConstants.METADATA_DATAVERSE_NAME,
                 MetadataConstants.FULL_TEXT_FILTER_DATASET_NAME) == null) {
-            insertMetadataDatasets(mdTxnCtx, new IMetadataIndex[] { MetadataPrimaryIndexes.FULL_TEXT_FILTER_DATASET });
+            insertMetadataDatasets(mdTxnCtx,
+                    new IMetadataIndex[] { metadataIndexesProvider.getFullTextFilterEntity().getIndex() });
         }
     }
 
@@ -376,14 +368,14 @@
     }
 
     /**
-     * Enlist a metadata index so it is available for metadata operations should be
-     * performed upon bootstrapping
+     * Enlist a metadata index so it is available for metadata operations should be performed upon bootstrapping
      *
      * @param index
+     * @param mdIndexesProvider
      * @throws HyracksDataException
      */
-    public static void enlistMetadataDataset(INCServiceContext ncServiceCtx, IMetadataIndex index)
-            throws HyracksDataException {
+    public static void enlistMetadataDataset(INCServiceContext ncServiceCtx, IMetadataIndex index,
+            MetadataIndexesProvider mdIndexesProvider) throws HyracksDataException {
         final int datasetId = index.getDatasetId().getId();
         String metadataPartitionPath =
                 StoragePathUtil.prepareStoragePartitionPath(MetadataNode.INSTANCE.getMetadataStoragePartition());
@@ -419,7 +411,7 @@
             resource = localResourceRepository.get(file.getRelativePath());
             createMetadataDataset = resource == null;
             if (createMetadataDataset) {
-                ensureCatalogUpgradability(index);
+                ensureCatalogUpgradability(index, mdIndexesProvider);
             }
         }
         if (createMetadataDataset) {
@@ -572,12 +564,12 @@
         MetadataBootstrap.isNewUniverse = isNewUniverse;
     }
 
-    private static void ensureCatalogUpgradability(IMetadataIndex index) {
-        if (index != MetadataPrimaryIndexes.SYNONYM_DATASET
+    private static void ensureCatalogUpgradability(IMetadataIndex index, MetadataIndexesProvider mdIndexesProvider) {
+        if (index != mdIndexesProvider.getSynonymEntity().getIndex()
                 // Backward-compatibility: FULLTEXT_ENTITY_DATASET is added to AsterixDB recently
                 // and may not exist in an older dataverse
-                && index != MetadataPrimaryIndexes.FULL_TEXT_CONFIG_DATASET
-                && index != MetadataPrimaryIndexes.FULL_TEXT_FILTER_DATASET) {
+                && index != mdIndexesProvider.getFullTextConfigEntity().getIndex()
+                && index != mdIndexesProvider.getFullTextFilterEntity().getIndex()) {
             throw new IllegalStateException(
                     "attempt to create metadata index " + index.getIndexName() + ". Index should already exist");
         }
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/MetadataBuiltinEntities.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/MetadataBuiltinEntities.java
index 938cb22..05b7c96 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/MetadataBuiltinEntities.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/MetadataBuiltinEntities.java
@@ -28,6 +28,8 @@
 
 public class MetadataBuiltinEntities {
     //--------------------------------------- Dataverses ----------------------------------------//
+    public static final Dataverse METADATA_DATAVERSE = new Dataverse(MetadataConstants.METADATA_DATAVERSE_NAME,
+            NonTaggedDataFormat.NON_TAGGED_DATA_FORMAT, MetadataUtil.PENDING_NO_OP);
     public static final DataverseName DEFAULT_DATAVERSE_NAME = DataverseName.createBuiltinDataverseName("Default");
     public static final Dataverse DEFAULT_DATAVERSE =
             new Dataverse(DEFAULT_DATAVERSE_NAME, NonTaggedDataFormat.class.getName(), MetadataUtil.PENDING_NO_OP);
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/MetadataIndexesProvider.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/MetadataIndexesProvider.java
new file mode 100644
index 0000000..63b6abf
--- /dev/null
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/MetadataIndexesProvider.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.asterix.metadata.bootstrap;
+
+import static org.apache.hyracks.control.common.controllers.ControllerConfig.Option.CLOUD_DEPLOYMENT;
+
+import org.apache.asterix.metadata.api.IMetadataIndex;
+import org.apache.hyracks.api.application.INCServiceContext;
+
+public class MetadataIndexesProvider {
+
+    protected final boolean cloudDeployment;
+
+    public MetadataIndexesProvider(INCServiceContext ncServiceCtx) {
+        cloudDeployment = ncServiceCtx.getAppConfig().getBoolean(CLOUD_DEPLOYMENT);
+    }
+
+    public DataverseEntity getDataverseEntity() {
+        return DataverseEntity.of(cloudDeployment);
+    }
+
+    public DatasetEntity getDatasetEntity() {
+        return DatasetEntity.of(cloudDeployment);
+    }
+
+    public DatatypeEntity getDatatypeEntity() {
+        return DatatypeEntity.of(cloudDeployment);
+    }
+
+    public IndexEntity getIndexEntity() {
+        return IndexEntity.of(cloudDeployment);
+    }
+
+    public SynonymEntity getSynonymEntity() {
+        return SynonymEntity.of(cloudDeployment);
+    }
+
+    public NodeEntity getNodeEntity() {
+        return NodeEntity.of(cloudDeployment);
+    }
+
+    public NodeGroupEntity getNodeGroupEntity() {
+        return NodeGroupEntity.of(cloudDeployment);
+    }
+
+    public FunctionEntity getFunctionEntity() {
+        return FunctionEntity.of(cloudDeployment);
+    }
+
+    public DatasourceAdapterEntity getDatasourceAdapterEntity() {
+        return DatasourceAdapterEntity.of(cloudDeployment);
+    }
+
+    public FeedEntity getFeedEntity() {
+        return FeedEntity.of(cloudDeployment);
+    }
+
+    public FeedPolicyEntity getFeedPolicyEntity() {
+        return FeedPolicyEntity.of(cloudDeployment);
+    }
+
+    public LibraryEntity getLibraryEntity() {
+        return LibraryEntity.of(cloudDeployment);
+    }
+
+    public CompactionPolicyEntity getCompactionPolicyEntity() {
+        return CompactionPolicyEntity.of(cloudDeployment);
+    }
+
+    public ExternalFileEntity getExternalFileEntity() {
+        return ExternalFileEntity.of(cloudDeployment);
+    }
+
+    public FeedConnectionEntity getFeedConnectionEntity() {
+        return FeedConnectionEntity.of(cloudDeployment);
+    }
+
+    public FullTextConfigEntity getFullTextConfigEntity() {
+        return FullTextConfigEntity.of(cloudDeployment);
+    }
+
+    public FullTextFilterEntity getFullTextFilterEntity() {
+        return FullTextFilterEntity.of(cloudDeployment);
+    }
+
+    public IMetadataIndex[] getMetadataIndexes() {
+        return new IMetadataIndex[] { getDataverseEntity().getIndex(), getDatasetEntity().getIndex(),
+                getDatatypeEntity().getIndex(), getIndexEntity().getIndex(), getSynonymEntity().getIndex(),
+                getNodeEntity().getIndex(), getNodeGroupEntity().getIndex(), getFunctionEntity().getIndex(),
+                getDatasourceAdapterEntity().getIndex(), getFeedEntity().getIndex(), getFeedPolicyEntity().getIndex(),
+                getLibraryEntity().getIndex(), getCompactionPolicyEntity().getIndex(),
+                getExternalFileEntity().getIndex(), getFeedConnectionEntity().getIndex(),
+                getFullTextConfigEntity().getIndex(), getFullTextFilterEntity().getIndex() };
+    }
+}
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/MetadataPrimaryIndexes.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/MetadataPrimaryIndexes.java
index a191e43..1c7c1e0 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/MetadataPrimaryIndexes.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/MetadataPrimaryIndexes.java
@@ -19,13 +19,8 @@
 
 package org.apache.asterix.metadata.bootstrap;
 
-import java.util.Arrays;
-
 import org.apache.asterix.common.metadata.MetadataIndexImmutableProperties;
-import org.apache.asterix.metadata.api.IMetadataIndex;
 import org.apache.asterix.metadata.utils.MetadataConstants;
-import org.apache.asterix.om.types.BuiltinType;
-import org.apache.asterix.om.types.IAType;
 
 /**
  * Contains static primary-index descriptors of all metadata datasets.
@@ -66,97 +61,6 @@
     public static final MetadataIndexImmutableProperties PROPERTIES_FULL_TEXT_FILTER =
             new MetadataIndexImmutableProperties(MetadataConstants.FULL_TEXT_FILTER_DATASET_NAME, 17, 17);
 
-    public static final IMetadataIndex DATAVERSE_DATASET =
-            new MetadataIndex(PROPERTIES_DATAVERSE, 2, new IAType[] { BuiltinType.ASTRING },
-                    Arrays.asList(Arrays.asList(MetadataRecordTypes.FIELD_NAME_DATAVERSE_NAME)), 0,
-                    MetadataRecordTypes.DATAVERSE_RECORDTYPE, true, new int[] { 0 });
-    public static final IMetadataIndex DATASET_DATASET =
-            new MetadataIndex(PROPERTIES_DATASET, 3, new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING },
-                    Arrays.asList(Arrays.asList(MetadataRecordTypes.FIELD_NAME_DATAVERSE_NAME),
-                            Arrays.asList(MetadataRecordTypes.FIELD_NAME_DATASET_NAME)),
-                    0, MetadataRecordTypes.DATASET_RECORDTYPE, true, new int[] { 0, 1 });
-    public static final IMetadataIndex DATATYPE_DATASET =
-            new MetadataIndex(PROPERTIES_DATATYPE, 3, new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING },
-                    Arrays.asList(Arrays.asList(MetadataRecordTypes.FIELD_NAME_DATAVERSE_NAME),
-                            Arrays.asList(MetadataRecordTypes.FIELD_NAME_DATATYPE_NAME)),
-                    0, MetadataRecordTypes.DATATYPE_RECORDTYPE, true, new int[] { 0, 1 });
-    public static final IMetadataIndex INDEX_DATASET = new MetadataIndex(PROPERTIES_INDEX, 4,
-            new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING, BuiltinType.ASTRING },
-            Arrays.asList(Arrays.asList(MetadataRecordTypes.FIELD_NAME_DATAVERSE_NAME),
-                    Arrays.asList(MetadataRecordTypes.FIELD_NAME_DATASET_NAME),
-                    Arrays.asList(MetadataRecordTypes.FIELD_NAME_INDEX_NAME)),
-            0, MetadataRecordTypes.INDEX_RECORDTYPE, true, new int[] { 0, 1, 2 });
-    public static final IMetadataIndex NODE_DATASET =
-            new MetadataIndex(PROPERTIES_NODE, 2, new IAType[] { BuiltinType.ASTRING },
-                    Arrays.asList(Arrays.asList(MetadataRecordTypes.FIELD_NAME_NODE_NAME)), 0,
-                    MetadataRecordTypes.NODE_RECORDTYPE, true, new int[] { 0 });
-    public static final IMetadataIndex NODEGROUP_DATASET =
-            new MetadataIndex(PROPERTIES_NODEGROUP, 2, new IAType[] { BuiltinType.ASTRING },
-                    Arrays.asList(Arrays.asList(MetadataRecordTypes.FIELD_NAME_GROUP_NAME)), 0,
-                    MetadataRecordTypes.NODEGROUP_RECORDTYPE, true, new int[] { 0 });
-    public static final IMetadataIndex FUNCTION_DATASET = new MetadataIndex(PROPERTIES_FUNCTION, 4,
-            new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING, BuiltinType.ASTRING },
-            Arrays.asList(Arrays.asList(MetadataRecordTypes.FIELD_NAME_DATAVERSE_NAME),
-                    Arrays.asList(MetadataRecordTypes.FIELD_NAME_NAME),
-                    Arrays.asList(MetadataRecordTypes.FIELD_NAME_ARITY)),
-            0, MetadataRecordTypes.FUNCTION_RECORDTYPE, true, new int[] { 0, 1, 2 });
-    public static final IMetadataIndex DATASOURCE_ADAPTER_DATASET = new MetadataIndex(PROPERTIES_DATASOURCE_ADAPTER, 3,
-            new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING },
-            Arrays.asList(Arrays.asList(MetadataRecordTypes.FIELD_NAME_DATAVERSE_NAME),
-                    Arrays.asList(MetadataRecordTypes.FIELD_NAME_NAME)),
-            0, MetadataRecordTypes.DATASOURCE_ADAPTER_RECORDTYPE, true, new int[] { 0, 1 });
-    public static final IMetadataIndex LIBRARY_DATASET =
-            new MetadataIndex(PROPERTIES_LIBRARY, 3, new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING },
-                    Arrays.asList(Arrays.asList(MetadataRecordTypes.FIELD_NAME_DATAVERSE_NAME),
-                            Arrays.asList(MetadataRecordTypes.FIELD_NAME_NAME)),
-                    0, MetadataRecordTypes.LIBRARY_RECORDTYPE, true, new int[] { 0, 1 });
-    public static final IMetadataIndex FEED_DATASET =
-            new MetadataIndex(PROPERTIES_FEED, 3, new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING },
-                    Arrays.asList(Arrays.asList(MetadataRecordTypes.FIELD_NAME_DATAVERSE_NAME),
-                            Arrays.asList(MetadataRecordTypes.FIELD_NAME_FEED_NAME)),
-                    0, MetadataRecordTypes.FEED_RECORDTYPE, true, new int[] { 0, 1 });
-    public static final IMetadataIndex FEED_ACTIVITY_DATASET = null;
-    public static final IMetadataIndex FEED_POLICY_DATASET =
-            new MetadataIndex(PROPERTIES_FEED_POLICY, 3, new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING },
-                    Arrays.asList(Arrays.asList(MetadataRecordTypes.FIELD_NAME_DATAVERSE_NAME),
-                            Arrays.asList(MetadataRecordTypes.FIELD_NAME_POLICY_NAME)),
-                    0, MetadataRecordTypes.FEED_POLICY_RECORDTYPE, true, new int[] { 0, 1 });
-    public static final IMetadataIndex COMPACTION_POLICY_DATASET = new MetadataIndex(PROPERTIES_COMPACTION_POLICY, 3,
-            new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING },
-            Arrays.asList(Arrays.asList(MetadataRecordTypes.FIELD_NAME_DATAVERSE_NAME),
-                    Arrays.asList(MetadataRecordTypes.FIELD_NAME_COMPACTION_POLICY)),
-            0, MetadataRecordTypes.COMPACTION_POLICY_RECORDTYPE, true, new int[] { 0, 1 });
-    public static final IMetadataIndex EXTERNAL_FILE_DATASET = new MetadataIndex(PROPERTIES_EXTERNAL_FILE, 4,
-            new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING, BuiltinType.AINT32 },
-            Arrays.asList(Arrays.asList(MetadataRecordTypes.FIELD_NAME_DATAVERSE_NAME),
-                    Arrays.asList(MetadataRecordTypes.FIELD_NAME_DATASET_NAME),
-                    Arrays.asList(MetadataRecordTypes.FIELD_NAME_FILE_NUMBER)),
-            0, MetadataRecordTypes.EXTERNAL_FILE_RECORDTYPE, true, new int[] { 0, 1, 2 });
-
-    public static final IMetadataIndex FEED_CONNECTION_DATASET = new MetadataIndex(PROPERTIES_FEED_CONNECTION, 4,
-            new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING, BuiltinType.ASTRING },
-            Arrays.asList(Arrays.asList(MetadataRecordTypes.FIELD_NAME_DATAVERSE_NAME),
-                    Arrays.asList(MetadataRecordTypes.FIELD_NAME_FEED_NAME),
-                    Arrays.asList(MetadataRecordTypes.FIELD_NAME_DATASET_NAME)),
-            0, MetadataRecordTypes.FEED_CONNECTION_RECORDTYPE, true, new int[] { 0, 1, 2 });
-
-    public static final IMetadataIndex SYNONYM_DATASET =
-            new MetadataIndex(PROPERTIES_SYNONYM, 3, new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING },
-                    Arrays.asList(Arrays.asList(MetadataRecordTypes.FIELD_NAME_DATAVERSE_NAME),
-                            Arrays.asList(MetadataRecordTypes.FIELD_NAME_SYNONYM_NAME)),
-                    0, MetadataRecordTypes.SYNONYM_RECORDTYPE, true, new int[] { 0, 1 });
-
-    public static final IMetadataIndex FULL_TEXT_CONFIG_DATASET =
-            new MetadataIndex(PROPERTIES_FULL_TEXT_CONFIG, 3, new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING },
-                    Arrays.asList(Arrays.asList(MetadataRecordTypes.FIELD_NAME_DATAVERSE_NAME),
-                            Arrays.asList(MetadataRecordTypes.FIELD_NAME_FULL_TEXT_CONFIG_NAME)),
-                    0, MetadataRecordTypes.FULL_TEXT_CONFIG_RECORDTYPE, true, new int[] { 0, 1 });
-    public static final IMetadataIndex FULL_TEXT_FILTER_DATASET =
-            new MetadataIndex(PROPERTIES_FULL_TEXT_FILTER, 3, new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING },
-                    Arrays.asList(Arrays.asList(MetadataRecordTypes.FIELD_NAME_DATAVERSE_NAME),
-                            Arrays.asList(MetadataRecordTypes.FIELD_NAME_FULL_TEXT_FILTER_NAME)),
-                    0, MetadataRecordTypes.FULL_TEXT_FILTER_RECORDTYPE, true, new int[] { 0, 1 });
-
     private MetadataPrimaryIndexes() {
     }
 }
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/MetadataRecordTypes.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/MetadataRecordTypes.java
index f1156f7..4f4d2b2 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/MetadataRecordTypes.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/MetadataRecordTypes.java
@@ -22,7 +22,6 @@
 import org.apache.asterix.om.types.AOrderedListType;
 import org.apache.asterix.om.types.ARecordType;
 import org.apache.asterix.om.types.AUnionType;
-import org.apache.asterix.om.types.AUnorderedListType;
 import org.apache.asterix.om.types.BuiltinType;
 import org.apache.asterix.om.types.IAType;
 
@@ -33,9 +32,7 @@
 
     //--------------------------------------- Fields Names --------------------------------------//
     public static final String FIELD_NAME_ADAPTER_CONFIGURATION = "AdapterConfiguration";
-    public static final String FIELD_NAME_ADAPTER_NAME = "AdapterName";
     public static final String FIELD_NAME_ARITY = "Arity";
-    public static final String FIELD_NAME_ARGS = "Arguments";
     public static final String FIELD_NAME_AUTOGENERATED = "Autogenerated";
     public static final String FIELD_NAME_CAST = "Cast";
     public static final String FIELD_NAME_CLASSNAME = "Classname";
@@ -56,7 +53,6 @@
     public static final String FIELD_NAME_DESCRIPTION = "Description";
     public static final String FIELD_NAME_EXTERNAL_DETAILS = "ExternalDetails";
     public static final String FIELD_NAME_FEED_NAME = "FeedName";
-    public static final String FIELD_NAME_FEED_TYPE = "FeedType";
     public static final String FIELD_NAME_FIELDS = "Fields";
     public static final String FIELD_NAME_FIELD_NAME = "FieldName";
     public static final String FIELD_NAME_FIELD_TYPE = "FieldType";
@@ -107,7 +103,6 @@
     public static final String FIELD_NAME_RETURN_TYPE = "ReturnType";
     public static final String FIELD_NAME_RETURN_TYPE_DATAVERSE_NAME = "ReturnTypeDataverseName";
     public static final String FIELD_NAME_SEARCH_KEY = "SearchKey";
-    public static final String FIELD_NAME_STATUS = "Status";
     public static final String FIELD_NAME_SYNONYM_NAME = "SynonymName";
     public static final String FIELD_NAME_TAG = "Tag";
     public static final String FIELD_NAME_TIMESTAMP = "Timestamp";
@@ -125,7 +120,6 @@
     public static final String FIELD_NAME_FULL_TEXT_TOKENIZER = "Tokenizer";
     public static final String FIELD_NAME_FULL_TEXT_FILTER_PIPELINE = "FullTextFilterPipeline";
     public static final String FIELD_NAME_FULL_TEXT_STOPWORD_LIST = "StopwordList";
-    public static final String FIELD_NAME_FULL_TEXT_STEMMER_LANGUAGE = "Language";
 
     //---------------------------------- Record Types Creation ----------------------------------//
     //--------------------------------------- Properties ----------------------------------------//
@@ -133,7 +127,6 @@
     public static final String PROPERTIES_NAME_FIELD_NAME = "name";
     public static final int PROPERTIES_VALUE_FIELD_INDEX = 1;
     public static final String PROPERTIES_VALUE_FIELD_NAME = "value";
-    public static final String TYPE_DV_FIELD_NAME = "Dataverse";
     public static final ARecordType POLICY_PARAMS_RECORDTYPE = createPropertiesRecordType();
     public static final ARecordType DATASOURCE_ADAPTER_PROPERTIES_RECORDTYPE = createPropertiesRecordType();
     public static final ARecordType COMPACTION_POLICY_PROPERTIES_RECORDTYPE = createPropertiesRecordType();
@@ -177,20 +170,6 @@
             true);
     //---------------------------------------- Dataset ------------------------------------------//
     public static final String RECORD_NAME_DATASET = "DatasetRecordType";
-    public static final int DATASET_ARECORD_DATAVERSENAME_FIELD_INDEX = 0;
-    public static final int DATASET_ARECORD_DATASETNAME_FIELD_INDEX = 1;
-    public static final int DATASET_ARECORD_DATATYPEDATAVERSENAME_FIELD_INDEX = 2;
-    public static final int DATASET_ARECORD_DATATYPENAME_FIELD_INDEX = 3;
-    public static final int DATASET_ARECORD_DATASETTYPE_FIELD_INDEX = 4;
-    public static final int DATASET_ARECORD_GROUPNAME_FIELD_INDEX = 5;
-    public static final int DATASET_ARECORD_COMPACTION_POLICY_FIELD_INDEX = 6;
-    public static final int DATASET_ARECORD_COMPACTION_POLICY_PROPERTIES_FIELD_INDEX = 7;
-    public static final int DATASET_ARECORD_INTERNALDETAILS_FIELD_INDEX = 8;
-    public static final int DATASET_ARECORD_EXTERNALDETAILS_FIELD_INDEX = 9;
-    public static final int DATASET_ARECORD_HINTS_FIELD_INDEX = 10;
-    public static final int DATASET_ARECORD_TIMESTAMP_FIELD_INDEX = 11;
-    public static final int DATASET_ARECORD_DATASETID_FIELD_INDEX = 12;
-    public static final int DATASET_ARECORD_PENDINGOP_FIELD_INDEX = 13;
     //Optional open fields
     public static final String DATASET_ARECORD_BLOCK_LEVEL_STORAGE_COMPRESSION_FIELD_NAME =
             "BlockLevelStorageCompression";
@@ -200,25 +179,6 @@
     public static final String DATASET_ARECORD_DATASET_FORMAT_FORMAT_FIELD_NAME = "Format";
     public static final String DATASET_ARECORD_DATASET_MAX_TUPLE_COUNT_FIELD_NAME = "MaxTupleCount";
     public static final String DATASET_ARECORD_DATASET_FREE_SPACE_TOLERANCE_FIELD_NAME = "FreeSpaceTolerance";
-    public static final ARecordType DATASET_RECORDTYPE = createRecordType(
-            // RecordTypeName
-            RECORD_NAME_DATASET,
-            // FieldNames
-            new String[] { FIELD_NAME_DATAVERSE_NAME, FIELD_NAME_DATASET_NAME, FIELD_NAME_DATATYPE_DATAVERSE_NAME,
-                    FIELD_NAME_DATATYPE_NAME, FIELD_NAME_DATASET_TYPE, FIELD_NAME_GROUP_NAME,
-                    FIELD_NAME_COMPACTION_POLICY, FIELD_NAME_COMPACTION_POLICY_PROPERTIES, FIELD_NAME_INTERNAL_DETAILS,
-                    FIELD_NAME_EXTERNAL_DETAILS, FIELD_NAME_HINTS, FIELD_NAME_TIMESTAMP, FIELD_NAME_DATASET_ID,
-                    FIELD_NAME_PENDING_OP },
-            // FieldTypes
-            new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING, BuiltinType.ASTRING, BuiltinType.ASTRING,
-                    BuiltinType.ASTRING, BuiltinType.ASTRING, BuiltinType.ASTRING,
-                    new AOrderedListType(COMPACTION_POLICY_PROPERTIES_RECORDTYPE, null),
-                    AUnionType.createUnknownableType(INTERNAL_DETAILS_RECORDTYPE),
-                    AUnionType.createUnknownableType(EXTERNAL_DETAILS_RECORDTYPE),
-                    new AUnorderedListType(DATASET_HINTS_RECORDTYPE, null), BuiltinType.ASTRING, BuiltinType.AINT32,
-                    BuiltinType.AINT32 },
-            //IsOpen?
-            true);
 
     //------------------------------------------ Field ------------------------------------------//
     public static final int FIELD_ARECORD_FIELDNAME_FIELD_INDEX = 0;
@@ -267,100 +227,21 @@
             true);
     //---------------------------------------- Data Type ----------------------------------------//
     public static final String RECORD_NAME_DATATYPE = "DatatypeRecordType";
-    public static final int DATATYPE_ARECORD_DATAVERSENAME_FIELD_INDEX = 0;
-    public static final int DATATYPE_ARECORD_DATATYPENAME_FIELD_INDEX = 1;
-    public static final int DATATYPE_ARECORD_DERIVED_FIELD_INDEX = 2;
-    public static final int DATATYPE_ARECORD_TIMESTAMP_FIELD_INDEX = 3;
-    public static final ARecordType DATATYPE_RECORDTYPE = createRecordType(
-            // RecordTypeName
-            RECORD_NAME_DATATYPE,
-            // FieldNames
-            new String[] { FIELD_NAME_DATAVERSE_NAME, FIELD_NAME_DATATYPE_NAME, FIELD_NAME_DERIVED,
-                    FIELD_NAME_TIMESTAMP },
-            // FieldTypes
-            new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING,
-                    AUnionType.createUnknownableType(DERIVEDTYPE_RECORDTYPE), BuiltinType.ASTRING },
-            //IsOpen?
-            true);
+
     //-------------------------------------- Dataverse ------------------------------------------//
     public static final String RECORD_NAME_DATAVERSE = "DataverseRecordType";
-    public static final int DATAVERSE_ARECORD_NAME_FIELD_INDEX = 0;
-    public static final int DATAVERSE_ARECORD_FORMAT_FIELD_INDEX = 1;
-    public static final int DATAVERSE_ARECORD_TIMESTAMP_FIELD_INDEX = 2;
-    public static final int DATAVERSE_ARECORD_PENDINGOP_FIELD_INDEX = 3;
-    public static final ARecordType DATAVERSE_RECORDTYPE = createRecordType(
-            // RecordTypeName
-            RECORD_NAME_DATAVERSE,
-            // FieldNames
-            new String[] { FIELD_NAME_DATAVERSE_NAME, FIELD_NAME_DATA_FORMAT, FIELD_NAME_TIMESTAMP,
-                    FIELD_NAME_PENDING_OP },
-            // FieldTypes
-            new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING, BuiltinType.ASTRING, BuiltinType.AINT32 },
-            //IsOpen?
-            true);
+
     //-------------------------------------------- Index ----------------------------------------//
     public static final String RECORD_NAME_INDEX = "IndexRecordType";
-    public static final int INDEX_ARECORD_DATAVERSENAME_FIELD_INDEX = 0;
-    public static final int INDEX_ARECORD_DATASETNAME_FIELD_INDEX = 1;
-    public static final int INDEX_ARECORD_INDEXNAME_FIELD_INDEX = 2;
-    public static final int INDEX_ARECORD_INDEXSTRUCTURE_FIELD_INDEX = 3;
-    public static final int INDEX_ARECORD_SEARCHKEY_FIELD_INDEX = 4;
-    public static final int INDEX_ARECORD_ISPRIMARY_FIELD_INDEX = 5;
-    public static final int INDEX_ARECORD_TIMESTAMP_FIELD_INDEX = 6;
-    public static final int INDEX_ARECORD_PENDINGOP_FIELD_INDEX = 7;
-    public static final ARecordType INDEX_RECORDTYPE = createRecordType(
-            // RecordTypeName
-            RECORD_NAME_INDEX,
-            // FieldNames
-            new String[] { FIELD_NAME_DATAVERSE_NAME, FIELD_NAME_DATASET_NAME, FIELD_NAME_INDEX_NAME,
-                    FIELD_NAME_INDEX_STRUCTURE, FIELD_NAME_SEARCH_KEY, FIELD_NAME_IS_PRIMARY, FIELD_NAME_TIMESTAMP,
-                    FIELD_NAME_PENDING_OP },
-            // FieldTypes
-            new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING, BuiltinType.ASTRING, BuiltinType.ASTRING,
-                    new AOrderedListType(new AOrderedListType(BuiltinType.ASTRING, null), null), BuiltinType.ABOOLEAN,
-                    BuiltinType.ASTRING, BuiltinType.AINT32 },
-            //IsOpen?
-            true);
+
     //----------------------------------------- Node --------------------------------------------//
     public static final String RECORD_NAME_NODE = "NodeRecordType";
-    public static final int NODE_ARECORD_NODENAME_FIELD_INDEX = 0;
-    public static final int NODE_ARECORD_NUMBEROFCORES_FIELD_INDEX = 1;
-    public static final int NODE_ARECORD_WORKINGMEMORYSIZE_FIELD_INDEX = 2;
-    public static final ARecordType NODE_RECORDTYPE = createRecordType(
-            // RecordTypeName
-            RECORD_NAME_NODE,
-            // FieldNames
-            new String[] { FIELD_NAME_NODE_NAME, FIELD_NAME_NUMBER_OF_CORES, FIELD_NAME_WORKING_MEMORY_SIZE },
-            // FieldTypes
-            new IAType[] { BuiltinType.ASTRING, BuiltinType.AINT64, BuiltinType.AINT64 },
-            //IsOpen?
-            true);
+
     //--------------------------------------- Node Group ----------------------------------------//
     public static final String RECORD_NAME_NODE_GROUP = "NodeGroupRecordType";
-    public static final int NODEGROUP_ARECORD_GROUPNAME_FIELD_INDEX = 0;
-    public static final int NODEGROUP_ARECORD_NODENAMES_FIELD_INDEX = 1;
-    public static final int NODEGROUP_ARECORD_TIMESTAMP_FIELD_INDEX = 2;
-    public static final ARecordType NODEGROUP_RECORDTYPE = createRecordType(
-            // RecordTypeName
-            RECORD_NAME_NODE_GROUP,
-            // FieldNames
-            new String[] { FIELD_NAME_GROUP_NAME, FIELD_NAME_NODE_NAMES, FIELD_NAME_TIMESTAMP },
-            // FieldTypes
-            new IAType[] { BuiltinType.ASTRING, new AUnorderedListType(BuiltinType.ASTRING, null),
-                    BuiltinType.ASTRING },
-            //IsOpen?
-            true);
+
     //----------------------------------------- Function ----------------------------------------//
     public static final String RECORD_NAME_FUNCTION = "FunctionRecordType";
-    public static final int FUNCTION_ARECORD_DATAVERSENAME_FIELD_INDEX = 0;
-    public static final int FUNCTION_ARECORD_FUNCTIONNAME_FIELD_INDEX = 1;
-    public static final int FUNCTION_ARECORD_FUNCTION_ARITY_FIELD_INDEX = 2;
-    public static final int FUNCTION_ARECORD_FUNCTION_PARAM_LIST_FIELD_INDEX = 3;
-    public static final int FUNCTION_ARECORD_FUNCTION_RETURN_TYPE_FIELD_INDEX = 4;
-    public static final int FUNCTION_ARECORD_FUNCTION_DEFINITION_FIELD_INDEX = 5;
-    public static final int FUNCTION_ARECORD_FUNCTION_LANGUAGE_FIELD_INDEX = 6;
-    public static final int FUNCTION_ARECORD_FUNCTION_KIND_FIELD_INDEX = 7;
-    public static final int FUNCTION_ARECORD_FUNCTION_DEPENDENCIES_FIELD_INDEX = 8;
     //open types
     public static final String FUNCTION_ARECORD_FUNCTION_RESOURCES_FIELD_NAME = "Resources";
     public static final String FUNCTION_ARECORD_FUNCTION_NULLCALL_FIELD_NAME = "NullCall";
@@ -372,198 +253,33 @@
     @Deprecated // back-compat
     public static final String FUNCTION_ARECORD_FUNCTION_WITHPARAMS_FIELD_NAME = "WithParams";
 
-    public static final ARecordType FUNCTION_RECORDTYPE = createRecordType(
-            // RecordTypeName
-            RECORD_NAME_FUNCTION,
-            // FieldNames
-            new String[] { FIELD_NAME_DATAVERSE_NAME, FIELD_NAME_NAME, FIELD_NAME_ARITY, FIELD_NAME_PARAMS,
-                    FIELD_NAME_RETURN_TYPE, FIELD_NAME_DEFINITION, FIELD_NAME_LANGUAGE, FIELD_NAME_KIND,
-                    FIELD_NAME_DEPENDENCIES },
-            // FieldTypes
-            new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING, BuiltinType.ASTRING,
-                    new AOrderedListType(BuiltinType.ASTRING, null), BuiltinType.ASTRING, BuiltinType.ASTRING,
-                    BuiltinType.ASTRING, BuiltinType.ASTRING,
-                    new AOrderedListType(new AOrderedListType(new AOrderedListType(BuiltinType.ASTRING, null), null),
-                            null) },
-            //IsOpen?
-            true);
     //------------------------------------------ Adapter ----------------------------------------//
     public static final String RECORD_NAME_DATASOURCE_ADAPTER = "DatasourceAdapterRecordType";
-    public static final int DATASOURCE_ADAPTER_ARECORD_DATAVERSENAME_FIELD_INDEX = 0;
-    public static final int DATASOURCE_ADAPTER_ARECORD_NAME_FIELD_INDEX = 1;
-    public static final int DATASOURCE_ADAPTER_ARECORD_CLASSNAME_FIELD_INDEX = 2;
-    public static final int DATASOURCE_ADAPTER_ARECORD_TYPE_FIELD_INDEX = 3;
-    public static final int DATASOURCE_ADAPTER_ARECORD_TIMESTAMP_FIELD_INDEX = 4;
-    //open types
-
-    public static final ARecordType DATASOURCE_ADAPTER_RECORDTYPE = createRecordType(
-            // RecordTypeName
-            RECORD_NAME_DATASOURCE_ADAPTER,
-            // FieldNames
-            new String[] { FIELD_NAME_DATAVERSE_NAME, FIELD_NAME_NAME, FIELD_NAME_CLASSNAME, FIELD_NAME_TYPE,
-                    FIELD_NAME_TIMESTAMP },
-            // FieldTypes
-            new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING, BuiltinType.ASTRING, BuiltinType.ASTRING,
-                    BuiltinType.ASTRING },
-            //IsOpen?
-            true);
 
     //---------------------------------------- Feed Details ------------------------------------//
     public static final String RECORD_NAME_FEED = "FeedRecordType";
-    public static final int FEED_ARECORD_DATAVERSE_NAME_FIELD_INDEX = 0;
-    public static final int FEED_ARECORD_FEED_NAME_FIELD_INDEX = 1;
-    public static final int FEED_ARECORD_ADAPTOR_CONFIG_INDEX = 2;
-    public static final int FEED_ARECORD_TIMESTAMP_FIELD_INDEX = 3;
-    public static final ARecordType FEED_RECORDTYPE = createRecordType(
-            // RecordTypeName
-            RECORD_NAME_FEED,
-            // FieldNames
-            new String[] { FIELD_NAME_DATAVERSE_NAME, FIELD_NAME_FEED_NAME, FIELD_NAME_ADAPTER_CONFIGURATION,
-                    FIELD_NAME_TIMESTAMP },
-            // FieldTypes
-            new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING,
-                    new AUnorderedListType(FEED_ADAPTER_CONFIGURATION_RECORDTYPE, null), BuiltinType.ASTRING },
-            //IsOpen?
-            true);
 
     //------------------------------------- Feed Connection ---------------------------------------//
     public static final String RECORD_NAME_FEED_CONNECTION = "FeedConnectionRecordType";
-    public static final int FEED_CONN_DATAVERSE_NAME_FIELD_INDEX = 0;
-    public static final int FEED_CONN_FEED_NAME_FIELD_INDEX = 1;
-    public static final int FEED_CONN_DATASET_NAME_FIELD_INDEX = 2;
-    public static final int FEED_CONN_OUTPUT_TYPE_INDEX = 3;
-    public static final int FEED_CONN_APPLIED_FUNCTIONS_FIELD_INDEX = 4;
-    public static final int FEED_CONN_POLICY_FIELD_INDEX = 5;
-
-    public static final ARecordType FEED_CONNECTION_RECORDTYPE = createRecordType(
-            // RecordTypeName
-            RECORD_NAME_FEED_CONNECTION,
-            // FieldNames
-            new String[] { FIELD_NAME_DATAVERSE_NAME, FIELD_NAME_FEED_NAME, FIELD_NAME_DATASET_NAME,
-                    FIELD_NAME_RETURN_TYPE, FIELD_NAME_APPLIED_FUNCTIONS, FIELD_NAME_POLICY_NAME },
-            // FieldTypes
-            new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING, BuiltinType.ASTRING, BuiltinType.ASTRING,
-                    new AUnorderedListType(BuiltinType.ASTRING, null), BuiltinType.ASTRING },
-            //IsOpen?
-            true);
 
     //------------------------------------- Feed Policy ---------------------------------------//
     public static final String RECORD_NAME_FEED_POLICY = "FeedPolicyRecordType";
-    public static final int FEED_POLICY_ARECORD_DATAVERSE_NAME_FIELD_INDEX = 0;
-    public static final int FEED_POLICY_ARECORD_POLICY_NAME_FIELD_INDEX = 1;
-    public static final int FEED_POLICY_ARECORD_DESCRIPTION_FIELD_INDEX = 2;
-    public static final int FEED_POLICY_ARECORD_PROPERTIES_FIELD_INDEX = 3;
-    public static final ARecordType FEED_POLICY_RECORDTYPE = createRecordType(
-            // RecordTypeName
-            RECORD_NAME_FEED_POLICY,
-            // FieldNames
-            new String[] { FIELD_NAME_DATAVERSE_NAME, FIELD_NAME_POLICY_NAME, FIELD_NAME_DESCRIPTION,
-                    FIELD_NAME_PROPERTIES },
-            // FieldTypes
-            new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING, BuiltinType.ASTRING,
-                    new AUnorderedListType(POLICY_PARAMS_RECORDTYPE, null) },
-            //IsOpen?
-            true);
+
     //---------------------------------------- Library ------------------------------------------//
     public static final String RECORD_NAME_LIBRARY = "LibraryRecordType";
-    public static final int LIBRARY_ARECORD_DATAVERSENAME_FIELD_INDEX = 0;
-    public static final int LIBRARY_ARECORD_NAME_FIELD_INDEX = 1;
-    public static final int LIBRARY_ARECORD_TIMESTAMP_FIELD_INDEX = 2;
-    public static final ARecordType LIBRARY_RECORDTYPE = createRecordType(
-            // RecordTypeName
-            RECORD_NAME_LIBRARY,
-            // FieldNames
-            new String[] { FIELD_NAME_DATAVERSE_NAME, FIELD_NAME_NAME, FIELD_NAME_TIMESTAMP },
-            // FieldTypes
-            new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING, BuiltinType.ASTRING },
-            //IsOpen?
-            true);
+
     //------------------------------------- Compaction Policy -----------------------------------//
     public static final String RECORD_NAME_COMPACTION_POLICY = "CompactionPolicyRecordType";
-    public static final int COMPACTION_POLICY_ARECORD_DATAVERSE_NAME_FIELD_INDEX = 0;
-    public static final int COMPACTION_POLICY_ARECORD_POLICY_NAME_FIELD_INDEX = 1;
-    public static final int COMPACTION_POLICY_ARECORD_CLASSNAME_FIELD_INDEX = 2;
-    public static final ARecordType COMPACTION_POLICY_RECORDTYPE = createRecordType(
-            // RecordTypeName
-            RECORD_NAME_COMPACTION_POLICY,
-            // FieldNames
-            new String[] { FIELD_NAME_DATAVERSE_NAME, FIELD_NAME_COMPACTION_POLICY, FIELD_NAME_CLASSNAME },
-            // FieldTypes
-            new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING, BuiltinType.ASTRING },
-            //IsOpen?
-            true);
+
     //-------------------------------------- ExternalFile ---------------------------------------//
     public static final String RECORD_NAME_EXTERNAL_FILE = "ExternalFileRecordType";
-    public static final int EXTERNAL_FILE_ARECORD_DATAVERSENAME_FIELD_INDEX = 0;
-    public static final int EXTERNAL_FILE_ARECORD_DATASET_NAME_FIELD_INDEX = 1;
-    public static final int EXTERNAL_FILE_ARECORD_FILE_NUMBER_FIELD_INDEX = 2;
-    public static final int EXTERNAL_FILE_ARECORD_FILE_NAME_FIELD_INDEX = 3;
-    public static final int EXTERNAL_FILE_ARECORD_FILE_SIZE_FIELD_INDEX = 4;
-    public static final int EXTERNAL_FILE_ARECORD_FILE_MOD_DATE_FIELD_INDEX = 5;
-    public static final int EXTERNAL_FILE_ARECORD_FILE_PENDING_OP_FIELD_INDEX = 6;
-    public static final ARecordType EXTERNAL_FILE_RECORDTYPE = createRecordType(
-            // RecordTypeName
-            RECORD_NAME_EXTERNAL_FILE,
-            // FieldNames
-            new String[] { FIELD_NAME_DATAVERSE_NAME, FIELD_NAME_DATASET_NAME, FIELD_NAME_FILE_NUMBER,
-                    FIELD_NAME_FILE_NAME, FIELD_NAME_FILE_SIZE, FIELD_NAME_FILE_MOD_TIME, FIELD_NAME_PENDING_OP },
-            // FieldTypes
-            new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING, BuiltinType.AINT32, BuiltinType.ASTRING,
-                    BuiltinType.AINT64, BuiltinType.ADATETIME, BuiltinType.AINT32 },
-            //IsOpen?
-            true);
 
     //-------------------------------------- Synonym ---------------------------------------//
     public static final String RECORD_NAME_SYNONYM = "SynonymRecordType";
-    public static final int SYNONYM_ARECORD_DATAVERSENAME_FIELD_INDEX = 0;
-    public static final int SYNONYM_ARECORD_SYNONYMNAME_FIELD_INDEX = 1;
-    public static final int SYNONYM_ARECORD_OBJECTDATAVERSENAME_FIELD_INDEX = 2;
-    public static final int SYNONYM_ARECORD_OBJECTNAME_FIELD_INDEX = 3;
-    public static final ARecordType SYNONYM_RECORDTYPE = createRecordType(
-            // RecordTypeName
-            RECORD_NAME_SYNONYM,
-            // FieldNames
-            new String[] { FIELD_NAME_DATAVERSE_NAME, FIELD_NAME_SYNONYM_NAME, FIELD_NAME_OBJECT_DATAVERSE_NAME,
-                    FIELD_NAME_OBJECT_NAME },
-            // FieldTypes
-            new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING, BuiltinType.ASTRING, BuiltinType.ASTRING },
-            //IsOpen?
-            true);
 
     //---------------------------------- FullText Config and Filter -------------------------//
-    public static final int FULL_TEXT_ARECORD_DATAVERSE_NAME_FIELD_INDEX = 0;
-
-    // FullText Config
-    public static final int FULL_TEXT_ARECORD_CONFIG_NAME_FIELD_INDEX = 1;
-    public static final int FULL_TEXT_ARECORD_CONFIG_TOKENIZER_FIELD_INDEX = 2;
-    public static final int FULL_TEXT_ARECORD_FILTER_PIPELINE_FIELD_INDEX = 3;
-
-    // FullText Filter
-    public static final int FULL_TEXT_ARECORD_FILTER_NAME_FIELD_INDEX = 1;
-    public static final int FULL_TEXT_ARECORD_FILTER_TYPE_FIELD_INDEX = 2;
-
-    // Stopword Filter
-    public static final int FULLTEXT_ENTITY_ARECORD_STOPWORD_LIST_FIELD_INDEX = 3;
-
-    // Stemmer Filter
-    public static final int FULLTEXT_ENTITY_ARECORD_STEMMER_LANGUAGE_FIELD_INDEX = 3;
-
     public static final String RECORD_NAME_FULL_TEXT_CONFIG = "FullTextConfigRecordType";
-    public static final ARecordType FULL_TEXT_CONFIG_RECORDTYPE = createRecordType(RECORD_NAME_FULL_TEXT_CONFIG,
-            new String[] { FIELD_NAME_DATAVERSE_NAME, FIELD_NAME_FULL_TEXT_CONFIG_NAME, FIELD_NAME_FULL_TEXT_TOKENIZER,
-                    FIELD_NAME_FULL_TEXT_FILTER_PIPELINE },
-            new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING, AUnionType.createNullableType(BuiltinType.ASTRING),
-                    AUnionType
-                            .createNullableType(new AOrderedListType(BuiltinType.ASTRING, "FullTextFilterPipeline")) },
-            true);
-
     public static final String RECORD_NAME_FULL_TEXT_FILTER = "FullTextFilterRecordType";
-    // Different filters may have different fields, e.g.
-    // stopwords filter has the stopwords list, so this type is OPEN
-    public static final ARecordType FULL_TEXT_FILTER_RECORDTYPE = createRecordType(RECORD_NAME_FULL_TEXT_FILTER,
-            new String[] { FIELD_NAME_DATAVERSE_NAME, FIELD_NAME_FULL_TEXT_FILTER_NAME,
-                    FIELD_NAME_FULL_TEXT_FILTER_TYPE },
-            new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING, BuiltinType.ASTRING }, true);
 
     // private members
     private MetadataRecordTypes() {
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/NodeEntity.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/NodeEntity.java
new file mode 100644
index 0000000..0b60366
--- /dev/null
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/NodeEntity.java
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.asterix.metadata.bootstrap;
+
+import static org.apache.asterix.metadata.bootstrap.MetadataPrimaryIndexes.PROPERTIES_NODE;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_NODE_NAME;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_NUMBER_OF_CORES;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_WORKING_MEMORY_SIZE;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.RECORD_NAME_NODE;
+
+import java.util.List;
+
+import org.apache.asterix.om.types.ARecordType;
+import org.apache.asterix.om.types.BuiltinType;
+import org.apache.asterix.om.types.IAType;
+
+public final class NodeEntity {
+
+    private static final NodeEntity NODE =
+            new NodeEntity(new MetadataIndex(PROPERTIES_NODE, 2, new IAType[] { BuiltinType.ASTRING },
+                    List.of(List.of(FIELD_NAME_NODE_NAME)), 0, nodeType(), true, new int[] { 0 }), 1, -1);
+
+    private final int payloadPosition;
+    private final MetadataIndex index;
+    private final int databaseNameIndex;
+    private final int nodeNameIndex;
+    private final int numberOfCoresIndex;
+    private final int memorySizeIndex;
+
+    private NodeEntity(MetadataIndex index, int payloadPosition, int startIndex) {
+        this.index = index;
+        this.payloadPosition = payloadPosition;
+        this.databaseNameIndex = startIndex++;
+        this.nodeNameIndex = startIndex++;
+        this.numberOfCoresIndex = startIndex++;
+        this.memorySizeIndex = startIndex++;
+    }
+
+    public static NodeEntity of(boolean cloudDeployment) {
+        return NODE;
+    }
+
+    public MetadataIndex getIndex() {
+        return index;
+    }
+
+    public ARecordType getRecordType() {
+        return index.getPayloadRecordType();
+    }
+
+    public int payloadPosition() {
+        return payloadPosition;
+    }
+
+    public int databaseNameIndex() {
+        return databaseNameIndex;
+    }
+
+    public int nodeNameIndex() {
+        return nodeNameIndex;
+    }
+
+    public int numberOfCoresIndex() {
+        return numberOfCoresIndex;
+    }
+
+    public int memorySizeIndex() {
+        return memorySizeIndex;
+    }
+
+    private static ARecordType nodeType() {
+        return MetadataRecordTypes.createRecordType(
+                // RecordTypeName
+                RECORD_NAME_NODE,
+                // FieldNames
+                new String[] { FIELD_NAME_NODE_NAME, FIELD_NAME_NUMBER_OF_CORES, FIELD_NAME_WORKING_MEMORY_SIZE },
+                // FieldTypes
+                new IAType[] { BuiltinType.ASTRING, BuiltinType.AINT64, BuiltinType.AINT64 },
+                //IsOpen?
+                true);
+    }
+}
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/NodeGroupEntity.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/NodeGroupEntity.java
new file mode 100644
index 0000000..8aa714c
--- /dev/null
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/NodeGroupEntity.java
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.asterix.metadata.bootstrap;
+
+import static org.apache.asterix.metadata.bootstrap.MetadataPrimaryIndexes.PROPERTIES_NODEGROUP;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_GROUP_NAME;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_NODE_NAMES;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_TIMESTAMP;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.RECORD_NAME_NODE_GROUP;
+
+import java.util.List;
+
+import org.apache.asterix.om.types.ARecordType;
+import org.apache.asterix.om.types.AUnorderedListType;
+import org.apache.asterix.om.types.BuiltinType;
+import org.apache.asterix.om.types.IAType;
+
+public final class NodeGroupEntity {
+
+    private static final NodeGroupEntity NODE_GROUP =
+            new NodeGroupEntity(new MetadataIndex(PROPERTIES_NODEGROUP, 2, new IAType[] { BuiltinType.ASTRING },
+                    List.of(List.of(FIELD_NAME_GROUP_NAME)), 0, nodeGroupType(), true, new int[] { 0 }), 1, -1);
+
+    private final int payloadPosition;
+    private final MetadataIndex index;
+    private final int databaseNameIndex;
+    private final int groupNameIndex;
+    private final int nodeNamesIndex;
+    private final int timestampIndex;
+
+    private NodeGroupEntity(MetadataIndex index, int payloadPosition, int startIndex) {
+        this.index = index;
+        this.payloadPosition = payloadPosition;
+        this.databaseNameIndex = startIndex++;
+        this.groupNameIndex = startIndex++;
+        this.nodeNamesIndex = startIndex++;
+        this.timestampIndex = startIndex++;
+    }
+
+    public static NodeGroupEntity of(boolean cloudDeployment) {
+        return NODE_GROUP;
+    }
+
+    public MetadataIndex getIndex() {
+        return index;
+    }
+
+    public ARecordType getRecordType() {
+        return index.getPayloadRecordType();
+    }
+
+    public int payloadPosition() {
+        return payloadPosition;
+    }
+
+    public int databaseNameIndex() {
+        return databaseNameIndex;
+    }
+
+    public int groupNameIndex() {
+        return groupNameIndex;
+    }
+
+    public int nodeNamesIndex() {
+        return nodeNamesIndex;
+    }
+
+    public int timestampIndex() {
+        return timestampIndex;
+    }
+
+    private static ARecordType nodeGroupType() {
+        return MetadataRecordTypes.createRecordType(
+                // RecordTypeName
+                RECORD_NAME_NODE_GROUP,
+                // FieldNames
+                new String[] { FIELD_NAME_GROUP_NAME, FIELD_NAME_NODE_NAMES, FIELD_NAME_TIMESTAMP },
+                // FieldTypes
+                new IAType[] { BuiltinType.ASTRING, new AUnorderedListType(BuiltinType.ASTRING, null),
+                        BuiltinType.ASTRING },
+                //IsOpen?
+                true);
+    }
+}
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/SynonymEntity.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/SynonymEntity.java
new file mode 100644
index 0000000..05bf114
--- /dev/null
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/SynonymEntity.java
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.asterix.metadata.bootstrap;
+
+import static org.apache.asterix.metadata.bootstrap.MetadataPrimaryIndexes.PROPERTIES_SYNONYM;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_DATAVERSE_NAME;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_OBJECT_DATAVERSE_NAME;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_OBJECT_NAME;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_SYNONYM_NAME;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.RECORD_NAME_SYNONYM;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.asterix.om.types.ARecordType;
+import org.apache.asterix.om.types.BuiltinType;
+import org.apache.asterix.om.types.IAType;
+
+public final class SynonymEntity {
+
+    private static final SynonymEntity SYNONYM = new SynonymEntity(
+            new MetadataIndex(PROPERTIES_SYNONYM, 3, new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING },
+                    Arrays.asList(List.of(FIELD_NAME_DATAVERSE_NAME), List.of(FIELD_NAME_SYNONYM_NAME)), 0,
+                    synonymType(), true, new int[] { 0, 1 }),
+            2, -1);
+
+    private final int payloadPosition;
+    private final MetadataIndex index;
+    private final int databaseNameIndex;
+    private final int dataverseNameIndex;
+    private final int synonymNameIndex;
+    private final int objectDataverseNameIndex;
+    private final int objectNameIndex;
+
+    private SynonymEntity(MetadataIndex index, int payloadPosition, int startIndex) {
+        this.index = index;
+        this.payloadPosition = payloadPosition;
+        this.databaseNameIndex = startIndex++;
+        this.dataverseNameIndex = startIndex++;
+        this.synonymNameIndex = startIndex++;
+        this.objectDataverseNameIndex = startIndex++;
+        this.objectNameIndex = startIndex++;;
+    }
+
+    public static SynonymEntity of(boolean cloudDeployment) {
+        return SYNONYM;
+    }
+
+    public MetadataIndex getIndex() {
+        return index;
+    }
+
+    public ARecordType getRecordType() {
+        return index.getPayloadRecordType();
+    }
+
+    public int payloadPosition() {
+        return payloadPosition;
+    }
+
+    public int databaseNameIndex() {
+        return databaseNameIndex;
+    }
+
+    public int dataverseNameIndex() {
+        return dataverseNameIndex;
+    }
+
+    public int synonymNameIndex() {
+        return synonymNameIndex;
+    }
+
+    public int objectDataverseNameIndex() {
+        return objectDataverseNameIndex;
+    }
+
+    public int objectNameIndex() {
+        return objectNameIndex;
+    }
+
+    private static ARecordType synonymType() {
+        return MetadataRecordTypes.createRecordType(
+                // RecordTypeName
+                RECORD_NAME_SYNONYM,
+                // FieldNames
+                new String[] { FIELD_NAME_DATAVERSE_NAME, FIELD_NAME_SYNONYM_NAME, FIELD_NAME_OBJECT_DATAVERSE_NAME,
+                        FIELD_NAME_OBJECT_NAME },
+                // FieldTypes
+                new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING, BuiltinType.ASTRING, BuiltinType.ASTRING },
+                //IsOpen?
+                true);
+    }
+}
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entities/Dataset.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entities/Dataset.java
index e8baeb1..b27ac38 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entities/Dataset.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entities/Dataset.java
@@ -134,7 +134,7 @@
     /*
      * Constants
      */
-    private static final long serialVersionUID = 2L;
+    private static final long serialVersionUID = 3L;
     private static final Logger LOGGER = LogManager.getLogger();
     private static final RTreeResourceFactoryProvider rTreeResourceFactoryProvider =
             RTreeResourceFactoryProvider.INSTANCE;
@@ -144,6 +144,7 @@
      * Members
      */
     private final int datasetId;
+    private final String databaseName = null;
     private final DataverseName dataverseName;
     private final String datasetName;
     private final DataverseName recordTypeDataverseName;
@@ -214,6 +215,10 @@
         this.datasetFormatInfo = datasetFormatInfo;
     }
 
+    public String getDatabaseName() {
+        return databaseName;
+    }
+
     @Override
     public DataverseName getDataverseName() {
         return dataverseName;
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/CompactionPolicyTupleTranslator.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/CompactionPolicyTupleTranslator.java
index 0acc91d..56a9a77 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/CompactionPolicyTupleTranslator.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/CompactionPolicyTupleTranslator.java
@@ -20,8 +20,7 @@
 package org.apache.asterix.metadata.entitytupletranslators;
 
 import org.apache.asterix.common.metadata.DataverseName;
-import org.apache.asterix.metadata.bootstrap.MetadataPrimaryIndexes;
-import org.apache.asterix.metadata.bootstrap.MetadataRecordTypes;
+import org.apache.asterix.metadata.bootstrap.CompactionPolicyEntity;
 import org.apache.asterix.metadata.entities.CompactionPolicy;
 import org.apache.asterix.om.base.ARecord;
 import org.apache.asterix.om.base.AString;
@@ -34,24 +33,24 @@
  */
 public class CompactionPolicyTupleTranslator extends AbstractTupleTranslator<CompactionPolicy> {
 
-    // Payload field containing serialized compactionPolicy.
-    private static final int COMPACTION_POLICY_PAYLOAD_TUPLE_FIELD_INDEX = 2;
+    private final CompactionPolicyEntity compactionPolicyEntity;
 
-    protected CompactionPolicyTupleTranslator(boolean getTuple) {
-        super(getTuple, MetadataPrimaryIndexes.COMPACTION_POLICY_DATASET, COMPACTION_POLICY_PAYLOAD_TUPLE_FIELD_INDEX);
+    protected CompactionPolicyTupleTranslator(boolean getTuple, CompactionPolicyEntity compactionPolicyEntity) {
+        super(getTuple, compactionPolicyEntity.getIndex(), compactionPolicyEntity.payloadPosition());
+        this.compactionPolicyEntity = compactionPolicyEntity;
     }
 
     @Override
     protected CompactionPolicy createMetadataEntityFromARecord(ARecord compactionPolicyRecord)
             throws AlgebricksException {
-        String dataverseCanonicalName = ((AString) compactionPolicyRecord
-                .getValueByPos(MetadataRecordTypes.COMPACTION_POLICY_ARECORD_DATAVERSE_NAME_FIELD_INDEX))
+        String dataverseCanonicalName =
+                ((AString) compactionPolicyRecord.getValueByPos(compactionPolicyEntity.dataverseNameIndex()))
                         .getStringValue();
         DataverseName dataverseName = DataverseName.createFromCanonicalForm(dataverseCanonicalName);
-        String policyName = ((AString) compactionPolicyRecord
-                .getValueByPos(MetadataRecordTypes.COMPACTION_POLICY_ARECORD_POLICY_NAME_FIELD_INDEX)).getStringValue();
-        String className = ((AString) compactionPolicyRecord
-                .getValueByPos(MetadataRecordTypes.COMPACTION_POLICY_ARECORD_CLASSNAME_FIELD_INDEX)).getStringValue();
+        String policyName = ((AString) compactionPolicyRecord.getValueByPos(compactionPolicyEntity.policyNameIndex()))
+                .getStringValue();
+        String className = ((AString) compactionPolicyRecord.getValueByPos(compactionPolicyEntity.classNameIndex()))
+                .getStringValue();
 
         return new CompactionPolicy(dataverseName, policyName, className);
     }
@@ -69,25 +68,25 @@
         stringSerde.serialize(aString, tupleBuilder.getDataOutput());
         tupleBuilder.addFieldEndOffset();
 
-        recordBuilder.reset(MetadataRecordTypes.COMPACTION_POLICY_RECORDTYPE);
+        recordBuilder.reset(compactionPolicyEntity.getRecordType());
 
         // write field 0
         fieldValue.reset();
         aString.setValue(dataverseCanonicalName);
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.COMPACTION_POLICY_ARECORD_DATAVERSE_NAME_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(compactionPolicyEntity.dataverseNameIndex(), fieldValue);
 
         // write field 1
         fieldValue.reset();
         aString.setValue(compactionPolicy.getPolicyName());
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.COMPACTION_POLICY_ARECORD_POLICY_NAME_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(compactionPolicyEntity.policyNameIndex(), fieldValue);
 
         // write field 2
         fieldValue.reset();
         aString.setValue(compactionPolicy.getClassName());
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.COMPACTION_POLICY_ARECORD_CLASSNAME_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(compactionPolicyEntity.classNameIndex(), fieldValue);
 
         // write record
         recordBuilder.write(tupleBuilder.getDataOutput(), true);
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/DatasetTupleTranslator.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/DatasetTupleTranslator.java
index 43fec57..37c7246 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/DatasetTupleTranslator.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/DatasetTupleTranslator.java
@@ -41,7 +41,7 @@
 import org.apache.asterix.common.metadata.DatasetFullyQualifiedName;
 import org.apache.asterix.common.metadata.DataverseName;
 import org.apache.asterix.metadata.IDatasetDetails;
-import org.apache.asterix.metadata.bootstrap.MetadataPrimaryIndexes;
+import org.apache.asterix.metadata.bootstrap.DatasetEntity;
 import org.apache.asterix.metadata.bootstrap.MetadataRecordTypes;
 import org.apache.asterix.metadata.dataset.DatasetFormatInfo;
 import org.apache.asterix.metadata.entities.Dataset;
@@ -87,15 +87,14 @@
  */
 public class DatasetTupleTranslator extends AbstractTupleTranslator<Dataset> {
 
-    // Payload field containing serialized Dataset.
-    private static final int DATASET_PAYLOAD_TUPLE_FIELD_INDEX = 2;
-
+    protected final DatasetEntity datasetEntity;
     protected AMutableInt32 aInt32;
     protected AMutableInt64 aInt64;
     protected AMutableDouble aDouble;
 
-    protected DatasetTupleTranslator(boolean getTuple) {
-        super(getTuple, MetadataPrimaryIndexes.DATASET_DATASET, DATASET_PAYLOAD_TUPLE_FIELD_INDEX);
+    protected DatasetTupleTranslator(boolean getTuple, DatasetEntity datasetEntity) {
+        super(getTuple, datasetEntity.getIndex(), datasetEntity.payloadPosition());
+        this.datasetEntity = datasetEntity;
         if (getTuple) {
             aInt32 = new AMutableInt32(-1);
             aInt64 = new AMutableInt64(-1);
@@ -105,39 +104,34 @@
 
     @Override
     protected Dataset createMetadataEntityFromARecord(ARecord datasetRecord) throws AlgebricksException {
+        ARecordType recType = datasetRecord.getType();
+        int databaseNameIndex = datasetEntity.databaseNameIndex();
+        String databaseName;
+        if (databaseNameIndex >= 0) {
+            databaseName = ((AString) datasetRecord.getValueByPos(databaseNameIndex)).getStringValue();
+        }
+
         String dataverseCanonicalName =
-                ((AString) datasetRecord.getValueByPos(MetadataRecordTypes.DATASET_ARECORD_DATAVERSENAME_FIELD_INDEX))
-                        .getStringValue();
+                ((AString) datasetRecord.getValueByPos(datasetEntity.dataverseNameIndex())).getStringValue();
         DataverseName dataverseName = DataverseName.createFromCanonicalForm(dataverseCanonicalName);
-        String datasetName =
-                ((AString) datasetRecord.getValueByPos(MetadataRecordTypes.DATASET_ARECORD_DATASETNAME_FIELD_INDEX))
-                        .getStringValue();
-        String typeName =
-                ((AString) datasetRecord.getValueByPos(MetadataRecordTypes.DATASET_ARECORD_DATATYPENAME_FIELD_INDEX))
-                        .getStringValue();
-        String typeDataverseCanonicalName = ((AString) datasetRecord
-                .getValueByPos(MetadataRecordTypes.DATASET_ARECORD_DATATYPEDATAVERSENAME_FIELD_INDEX)).getStringValue();
+        String datasetName = ((AString) datasetRecord.getValueByPos(datasetEntity.datasetNameIndex())).getStringValue();
+        String typeName = ((AString) datasetRecord.getValueByPos(datasetEntity.datatypeNameIndex())).getStringValue();
+        String typeDataverseCanonicalName =
+                ((AString) datasetRecord.getValueByPos(datasetEntity.datatypeDataverseNameIndex())).getStringValue();
         DataverseName typeDataverseName = DataverseName.createFromCanonicalForm(typeDataverseCanonicalName);
-        DatasetType datasetType = DatasetType.valueOf(
-                ((AString) datasetRecord.getValueByPos(MetadataRecordTypes.DATASET_ARECORD_DATASETTYPE_FIELD_INDEX))
-                        .getStringValue());
+        DatasetType datasetType = DatasetType
+                .valueOf(((AString) datasetRecord.getValueByPos(datasetEntity.datasetTypeIndex())).getStringValue());
         IDatasetDetails datasetDetails = null;
-        int datasetId =
-                ((AInt32) datasetRecord.getValueByPos(MetadataRecordTypes.DATASET_ARECORD_DATASETID_FIELD_INDEX))
-                        .getIntegerValue();
-        int pendingOp =
-                ((AInt32) datasetRecord.getValueByPos(MetadataRecordTypes.DATASET_ARECORD_PENDINGOP_FIELD_INDEX))
-                        .getIntegerValue();
-        String nodeGroupName =
-                ((AString) datasetRecord.getValueByPos(MetadataRecordTypes.DATASET_ARECORD_GROUPNAME_FIELD_INDEX))
-                        .getStringValue();
+        int datasetId = ((AInt32) datasetRecord.getValueByPos(datasetEntity.datasetIdIndex())).getIntegerValue();
+        int pendingOp = ((AInt32) datasetRecord.getValueByPos(datasetEntity.pendingOpIndex())).getIntegerValue();
+        String nodeGroupName = ((AString) datasetRecord.getValueByPos(datasetEntity.groupNameIndex())).getStringValue();
 
         Pair<String, Map<String, String>> compactionPolicy = readCompactionPolicy(datasetType, datasetRecord);
 
         switch (datasetType) {
             case INTERNAL: {
-                ARecord datasetDetailsRecord = (ARecord) datasetRecord
-                        .getValueByPos(MetadataRecordTypes.DATASET_ARECORD_INTERNALDETAILS_FIELD_INDEX);
+                ARecord datasetDetailsRecord =
+                        (ARecord) datasetRecord.getValueByPos(datasetEntity.internalDetailsIndex());
                 FileStructure fileStructure = FileStructure.valueOf(((AString) datasetDetailsRecord
                         .getValueByPos(MetadataRecordTypes.INTERNAL_DETAILS_ARECORD_FILESTRUCTURE_FIELD_INDEX))
                                 .getStringValue());
@@ -227,8 +221,8 @@
             }
 
             case EXTERNAL: {
-                ARecord datasetDetailsRecord = (ARecord) datasetRecord
-                        .getValueByPos(MetadataRecordTypes.DATASET_ARECORD_EXTERNALDETAILS_FIELD_INDEX);
+                ARecord datasetDetailsRecord =
+                        (ARecord) datasetRecord.getValueByPos(datasetEntity.externalDetailsIndex());
                 String adapter = ((AString) datasetDetailsRecord
                         .getValueByPos(MetadataRecordTypes.EXTERNAL_DETAILS_ARECORD_DATASOURCE_ADAPTER_FIELD_INDEX))
                                 .getStringValue();
@@ -258,8 +252,7 @@
                 break;
             }
             case VIEW: {
-                int datasetDetailsFieldPos =
-                        datasetRecord.getType().getFieldIndex(MetadataRecordTypes.FIELD_NAME_VIEW_DETAILS);
+                int datasetDetailsFieldPos = recType.getFieldIndex(MetadataRecordTypes.FIELD_NAME_VIEW_DETAILS);
                 ARecord datasetDetailsRecord = (ARecord) datasetRecord.getValueByPos(datasetDetailsFieldPos);
 
                 // Definition
@@ -376,13 +369,12 @@
 
         DataverseName metaTypeDataverseName = null;
         String metaTypeName = null;
-        int metaTypeDataverseNameIndex =
-                datasetRecord.getType().getFieldIndex(MetadataRecordTypes.FIELD_NAME_METATYPE_DATAVERSE_NAME);
+        int metaTypeDataverseNameIndex = recType.getFieldIndex(MetadataRecordTypes.FIELD_NAME_METATYPE_DATAVERSE_NAME);
         if (metaTypeDataverseNameIndex >= 0) {
             String metaTypeDataverseCanonicalName =
                     ((AString) datasetRecord.getValueByPos(metaTypeDataverseNameIndex)).getStringValue();
             metaTypeDataverseName = DataverseName.createFromCanonicalForm(metaTypeDataverseCanonicalName);
-            int metaTypeNameIndex = datasetRecord.getType().getFieldIndex(MetadataRecordTypes.FIELD_NAME_METATYPE_NAME);
+            int metaTypeNameIndex = recType.getFieldIndex(MetadataRecordTypes.FIELD_NAME_METATYPE_NAME);
             metaTypeName = ((AString) datasetRecord.getValueByPos(metaTypeNameIndex)).getStringValue();
         }
 
@@ -397,10 +389,10 @@
 
     protected Pair<String, Map<String, String>> readCompactionPolicy(DatasetType datasetType, ARecord datasetRecord) {
 
-        String compactionPolicy = ((AString) datasetRecord
-                .getValueByPos(MetadataRecordTypes.DATASET_ARECORD_COMPACTION_POLICY_FIELD_INDEX)).getStringValue();
-        AOrderedList compactionPolicyPropertiesList = ((AOrderedList) datasetRecord
-                .getValueByPos(MetadataRecordTypes.DATASET_ARECORD_COMPACTION_POLICY_PROPERTIES_FIELD_INDEX));
+        String compactionPolicy =
+                ((AString) datasetRecord.getValueByPos(datasetEntity.compactionPolicyIndex())).getStringValue();
+        AOrderedList compactionPolicyPropertiesList =
+                ((AOrderedList) datasetRecord.getValueByPos(datasetEntity.compactionPolicyPropertiesIndex()));
 
         Map<String, String> compactionPolicyProperties;
         if (compactionPolicyPropertiesList.size() > 0) {
@@ -484,56 +476,69 @@
     public ITupleReference getTupleFromMetadataEntity(Dataset dataset) throws HyracksDataException {
         OrderedListBuilder listBuilder = new OrderedListBuilder();
         ArrayBackedValueStorage itemValue = new ArrayBackedValueStorage();
+        String databaseName = dataset.getDatabaseName();
         String dataverseCanonicalName = dataset.getDataverseName().getCanonicalForm();
+        String datasetName = dataset.getDatasetName();
 
         // write the key in the first 2 fields of the tuple
         tupleBuilder.reset();
+        if (datasetEntity.databaseNameIndex() >= 0) {
+            aString.setValue(databaseName);
+            stringSerde.serialize(aString, tupleBuilder.getDataOutput());
+            tupleBuilder.addFieldEndOffset();
+        }
         aString.setValue(dataverseCanonicalName);
         stringSerde.serialize(aString, tupleBuilder.getDataOutput());
         tupleBuilder.addFieldEndOffset();
-        aString.setValue(dataset.getDatasetName());
+        aString.setValue(datasetName);
         stringSerde.serialize(aString, tupleBuilder.getDataOutput());
         tupleBuilder.addFieldEndOffset();
 
         // write the pay-load in the third field of the tuple
 
-        recordBuilder.reset(MetadataRecordTypes.DATASET_RECORDTYPE);
+        recordBuilder.reset(datasetEntity.getRecordType());
 
         // write field 0
+        if (datasetEntity.databaseNameIndex() >= 0) {
+            fieldValue.reset();
+            aString.setValue(databaseName);
+            stringSerde.serialize(aString, fieldValue.getDataOutput());
+            recordBuilder.addField(datasetEntity.databaseNameIndex(), fieldValue);
+        }
         fieldValue.reset();
         aString.setValue(dataverseCanonicalName);
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.DATASET_ARECORD_DATAVERSENAME_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(datasetEntity.dataverseNameIndex(), fieldValue);
 
         // write field 1
         fieldValue.reset();
-        aString.setValue(dataset.getDatasetName());
+        aString.setValue(datasetName);
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.DATASET_ARECORD_DATASETNAME_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(datasetEntity.datasetNameIndex(), fieldValue);
 
         // write field 2
         fieldValue.reset();
         aString.setValue(dataset.getItemTypeDataverseName().getCanonicalForm());
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.DATASET_ARECORD_DATATYPEDATAVERSENAME_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(datasetEntity.datatypeDataverseNameIndex(), fieldValue);
 
         // write field 3
         fieldValue.reset();
         aString.setValue(dataset.getItemTypeName());
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.DATASET_ARECORD_DATATYPENAME_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(datasetEntity.datatypeNameIndex(), fieldValue);
 
         // write field 4
         fieldValue.reset();
         aString.setValue(dataset.getDatasetType().toString());
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.DATASET_ARECORD_DATASETTYPE_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(datasetEntity.datasetTypeIndex(), fieldValue);
 
         // write field 5
         fieldValue.reset();
         aString.setValue(dataset.getNodeGroupName());
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.DATASET_ARECORD_GROUPNAME_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(datasetEntity.groupNameIndex(), fieldValue);
 
         // write field 6/7
         writeCompactionPolicy(dataset.getDatasetType(), dataset.getCompactionPolicy(),
@@ -544,20 +549,20 @@
             case INTERNAL:
                 fieldValue.reset();
                 dataset.getDatasetDetails().writeDatasetDetailsRecordType(fieldValue.getDataOutput());
-                recordBuilder.addField(MetadataRecordTypes.DATASET_ARECORD_INTERNALDETAILS_FIELD_INDEX, fieldValue);
+                recordBuilder.addField(datasetEntity.internalDetailsIndex(), fieldValue);
                 break;
             case EXTERNAL:
                 fieldValue.reset();
                 dataset.getDatasetDetails().writeDatasetDetailsRecordType(fieldValue.getDataOutput());
-                recordBuilder.addField(MetadataRecordTypes.DATASET_ARECORD_EXTERNALDETAILS_FIELD_INDEX, fieldValue);
+                recordBuilder.addField(datasetEntity.externalDetailsIndex(), fieldValue);
                 break;
             // VIEW details are written later by {@code writeOpenFields()}
         }
 
         // write field 10
         UnorderedListBuilder uListBuilder = new UnorderedListBuilder();
-        uListBuilder.reset((AUnorderedListType) MetadataRecordTypes.DATASET_RECORDTYPE
-                .getFieldTypes()[MetadataRecordTypes.DATASET_ARECORD_HINTS_FIELD_INDEX]);
+        uListBuilder
+                .reset((AUnorderedListType) datasetEntity.getRecordType().getFieldTypes()[datasetEntity.hintsIndex()]);
         for (Map.Entry<String, String> property : dataset.getHints().entrySet()) {
             String name = property.getKey();
             String value = property.getValue();
@@ -567,25 +572,25 @@
         }
         fieldValue.reset();
         uListBuilder.write(fieldValue.getDataOutput(), true);
-        recordBuilder.addField(MetadataRecordTypes.DATASET_ARECORD_HINTS_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(datasetEntity.hintsIndex(), fieldValue);
 
         // write field 11
         fieldValue.reset();
         aString.setValue(Calendar.getInstance().getTime().toString());
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.DATASET_ARECORD_TIMESTAMP_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(datasetEntity.timestampIndex(), fieldValue);
 
         // write field 12
         fieldValue.reset();
         aInt32.setValue(dataset.getDatasetId());
         int32Serde.serialize(aInt32, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.DATASET_ARECORD_DATASETID_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(datasetEntity.datasetIdIndex(), fieldValue);
 
         // write field 13
         fieldValue.reset();
         aInt32.setValue(dataset.getPendingOp());
         int32Serde.serialize(aInt32, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.DATASET_ARECORD_PENDINGOP_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(datasetEntity.pendingOpIndex(), fieldValue);
 
         // write open fields
         writeOpenFields(dataset);
@@ -605,11 +610,11 @@
         fieldValue.reset();
         aString.setValue(compactionPolicy);
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.DATASET_ARECORD_COMPACTION_POLICY_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(datasetEntity.compactionPolicyIndex(), fieldValue);
 
         // write field 7
-        listBuilder.reset((AOrderedListType) MetadataRecordTypes.DATASET_RECORDTYPE
-                .getFieldTypes()[MetadataRecordTypes.DATASET_ARECORD_COMPACTION_POLICY_PROPERTIES_FIELD_INDEX]);
+        listBuilder.reset((AOrderedListType) datasetEntity.getRecordType().getFieldTypes()[datasetEntity
+                .compactionPolicyPropertiesIndex()]);
         if (compactionPolicyProperties != null && !compactionPolicyProperties.isEmpty()) {
             for (Map.Entry<String, String> property : compactionPolicyProperties.entrySet()) {
                 String name = property.getKey();
@@ -622,8 +627,7 @@
         }
         fieldValue.reset();
         listBuilder.write(fieldValue.getDataOutput(), true);
-        recordBuilder.addField(MetadataRecordTypes.DATASET_ARECORD_COMPACTION_POLICY_PROPERTIES_FIELD_INDEX,
-                fieldValue);
+        recordBuilder.addField(datasetEntity.compactionPolicyPropertiesIndex(), fieldValue);
     }
 
     /**
@@ -751,8 +755,7 @@
         Map<String, String> hints = new HashMap<>();
         String key;
         String value;
-        AUnorderedList list =
-                (AUnorderedList) datasetRecord.getValueByPos(MetadataRecordTypes.DATASET_ARECORD_HINTS_FIELD_INDEX);
+        AUnorderedList list = (AUnorderedList) datasetRecord.getValueByPos(datasetEntity.hintsIndex());
         IACursor cursor = list.getCursor();
         while (cursor.next()) {
             ARecord field = (ARecord) cursor.get();
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/DatasourceAdapterTupleTranslator.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/DatasourceAdapterTupleTranslator.java
index 5d80796..e59041e 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/DatasourceAdapterTupleTranslator.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/DatasourceAdapterTupleTranslator.java
@@ -24,7 +24,7 @@
 import org.apache.asterix.common.external.IDataSourceAdapter;
 import org.apache.asterix.common.metadata.DataverseName;
 import org.apache.asterix.external.dataset.adapter.AdapterIdentifier;
-import org.apache.asterix.metadata.bootstrap.MetadataPrimaryIndexes;
+import org.apache.asterix.metadata.bootstrap.DatasourceAdapterEntity;
 import org.apache.asterix.metadata.bootstrap.MetadataRecordTypes;
 import org.apache.asterix.metadata.entities.DatasourceAdapter;
 import org.apache.asterix.om.base.ARecord;
@@ -35,27 +35,24 @@
 
 public class DatasourceAdapterTupleTranslator extends AbstractTupleTranslator<DatasourceAdapter> {
 
-    // Payload field containing serialized Adapter.
-    private static final int ADAPTER_PAYLOAD_TUPLE_FIELD_INDEX = 2;
+    private final DatasourceAdapterEntity datasourceAdapterEntity;
 
-    protected DatasourceAdapterTupleTranslator(boolean getTuple) {
-        super(getTuple, MetadataPrimaryIndexes.DATASOURCE_ADAPTER_DATASET, ADAPTER_PAYLOAD_TUPLE_FIELD_INDEX);
+    protected DatasourceAdapterTupleTranslator(boolean getTuple, DatasourceAdapterEntity datasourceAdapterEntity) {
+        super(getTuple, datasourceAdapterEntity.getIndex(), datasourceAdapterEntity.payloadPosition());
+        this.datasourceAdapterEntity = datasourceAdapterEntity;
     }
 
     @Override
     protected DatasourceAdapter createMetadataEntityFromARecord(ARecord adapterRecord) throws AlgebricksException {
-        String dataverseCanonicalName = ((AString) adapterRecord
-                .getValueByPos(MetadataRecordTypes.DATASOURCE_ADAPTER_ARECORD_DATAVERSENAME_FIELD_INDEX))
-                        .getStringValue();
+        String dataverseCanonicalName =
+                ((AString) adapterRecord.getValueByPos(datasourceAdapterEntity.dataverseNameIndex())).getStringValue();
         DataverseName dataverseName = DataverseName.createFromCanonicalForm(dataverseCanonicalName);
         String adapterName =
-                ((AString) adapterRecord.getValueByPos(MetadataRecordTypes.DATASOURCE_ADAPTER_ARECORD_NAME_FIELD_INDEX))
-                        .getStringValue();
-        String classname = ((AString) adapterRecord
-                .getValueByPos(MetadataRecordTypes.DATASOURCE_ADAPTER_ARECORD_CLASSNAME_FIELD_INDEX)).getStringValue();
-        IDataSourceAdapter.AdapterType adapterType = IDataSourceAdapter.AdapterType.valueOf(
-                ((AString) adapterRecord.getValueByPos(MetadataRecordTypes.DATASOURCE_ADAPTER_ARECORD_TYPE_FIELD_INDEX))
-                        .getStringValue());
+                ((AString) adapterRecord.getValueByPos(datasourceAdapterEntity.adapterNameIndex())).getStringValue();
+        String classname =
+                ((AString) adapterRecord.getValueByPos(datasourceAdapterEntity.classNameIndex())).getStringValue();
+        IDataSourceAdapter.AdapterType adapterType = IDataSourceAdapter.AdapterType
+                .valueOf(((AString) adapterRecord.getValueByPos(datasourceAdapterEntity.typeIndex())).getStringValue());
 
         DataverseName libraryDataverseName = null;
         String libraryName = null;
@@ -91,37 +88,37 @@
 
         // write the pay-load in the third field of the tuple
 
-        recordBuilder.reset(MetadataRecordTypes.DATASOURCE_ADAPTER_RECORDTYPE);
+        recordBuilder.reset(datasourceAdapterEntity.getRecordType());
 
         // write field 0
         fieldValue.reset();
         aString.setValue(dataverseCanonicalName);
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.DATASOURCE_ADAPTER_ARECORD_DATAVERSENAME_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(datasourceAdapterEntity.dataverseNameIndex(), fieldValue);
 
         // write field 1
         fieldValue.reset();
         aString.setValue(adapterIdentifier.getName());
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.DATASOURCE_ADAPTER_ARECORD_NAME_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(datasourceAdapterEntity.adapterNameIndex(), fieldValue);
 
         // write field 2
         fieldValue.reset();
         aString.setValue(adapter.getClassname());
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.DATASOURCE_ADAPTER_ARECORD_CLASSNAME_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(datasourceAdapterEntity.classNameIndex(), fieldValue);
 
         // write field 3
         fieldValue.reset();
         aString.setValue(adapter.getType().name());
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.DATASOURCE_ADAPTER_ARECORD_TYPE_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(datasourceAdapterEntity.typeIndex(), fieldValue);
 
         // write field 4
         fieldValue.reset();
         aString.setValue(Calendar.getInstance().getTime().toString());
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.DATASOURCE_ADAPTER_ARECORD_TIMESTAMP_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(datasourceAdapterEntity.timestampIndex(), fieldValue);
 
         // write open fields
         writeOpenFields(adapter);
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/DatatypeTupleTranslator.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/DatatypeTupleTranslator.java
index d10d25b..dc4fd59 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/DatatypeTupleTranslator.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/DatatypeTupleTranslator.java
@@ -24,7 +24,7 @@
 import org.apache.asterix.common.metadata.DataverseName;
 import org.apache.asterix.common.transactions.TxnId;
 import org.apache.asterix.metadata.MetadataNode;
-import org.apache.asterix.metadata.bootstrap.MetadataPrimaryIndexes;
+import org.apache.asterix.metadata.bootstrap.DatatypeEntity;
 import org.apache.asterix.metadata.bootstrap.MetadataRecordTypes;
 import org.apache.asterix.metadata.entities.Datatype;
 import org.apache.asterix.metadata.utils.TypeUtil;
@@ -48,28 +48,25 @@
  */
 public class DatatypeTupleTranslator extends AbstractDatatypeTupleTranslator<Datatype> {
 
-    // Payload field containing serialized Datatype.
-    private static final int DATATYPE_PAYLOAD_TUPLE_FIELD_INDEX = 2;
+    private final DatatypeEntity datatypeEntity;
 
-    protected DatatypeTupleTranslator(TxnId txnId, MetadataNode metadataNode, boolean getTuple) {
-        super(txnId, metadataNode, getTuple, MetadataPrimaryIndexes.DATATYPE_DATASET,
-                DATATYPE_PAYLOAD_TUPLE_FIELD_INDEX);
+    protected DatatypeTupleTranslator(TxnId txnId, MetadataNode metadataNode, boolean getTuple,
+            DatatypeEntity datatypeEntity) {
+        super(txnId, metadataNode, getTuple, datatypeEntity.getIndex(), datatypeEntity.payloadPosition());
+        this.datatypeEntity = datatypeEntity;
     }
 
     @Override
     protected Datatype createMetadataEntityFromARecord(ARecord datatypeRecord) throws AlgebricksException {
         String dataverseCanonicalName =
-                ((AString) datatypeRecord.getValueByPos(MetadataRecordTypes.DATATYPE_ARECORD_DATAVERSENAME_FIELD_INDEX))
-                        .getStringValue();
+                ((AString) datatypeRecord.getValueByPos(datatypeEntity.dataverseNameIndex())).getStringValue();
         DataverseName dataverseName = DataverseName.createFromCanonicalForm(dataverseCanonicalName);
         String datatypeName =
-                ((AString) datatypeRecord.getValueByPos(MetadataRecordTypes.DATATYPE_ARECORD_DATATYPENAME_FIELD_INDEX))
-                        .getStringValue();
+                ((AString) datatypeRecord.getValueByPos(datatypeEntity.datatypeNameIndex())).getStringValue();
         IAType type = BuiltinTypeMap.getBuiltinType(datatypeName);
         if (type == null) {
             // Derived Type
-            ARecord derivedTypeRecord =
-                    (ARecord) datatypeRecord.getValueByPos(MetadataRecordTypes.DATATYPE_ARECORD_DERIVED_FIELD_INDEX);
+            ARecord derivedTypeRecord = (ARecord) datatypeRecord.getValueByPos(datatypeEntity.derivedIndex());
             DerivedTypeTag tag = DerivedTypeTag.valueOf(
                     ((AString) derivedTypeRecord.getValueByPos(MetadataRecordTypes.DERIVEDTYPE_ARECORD_TAG_FIELD_INDEX))
                             .getStringValue());
@@ -156,19 +153,19 @@
         tupleBuilder.addFieldEndOffset();
 
         // write the payload in the third field of the tuple
-        recordBuilder.reset(MetadataRecordTypes.DATATYPE_RECORDTYPE);
+        recordBuilder.reset(datatypeEntity.getRecordType());
 
         // write field 0
         fieldValue.reset();
         aString.setValue(dataverseCanonicalName);
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.DATATYPE_ARECORD_DATAVERSENAME_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(datatypeEntity.dataverseNameIndex(), fieldValue);
 
         // write field 1
         fieldValue.reset();
         aString.setValue(dataType.getDatatypeName());
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.DATATYPE_ARECORD_DATATYPENAME_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(datatypeEntity.datatypeNameIndex(), fieldValue);
 
         // write field 2
         IAType fieldType = dataType.getDatatype();
@@ -176,14 +173,14 @@
             fieldValue.reset();
             writeDerivedTypeRecord(dataType.getDataverseName(), (AbstractComplexType) fieldType,
                     fieldValue.getDataOutput(), dataType.getIsAnonymous());
-            recordBuilder.addField(MetadataRecordTypes.DATATYPE_ARECORD_DERIVED_FIELD_INDEX, fieldValue);
+            recordBuilder.addField(datatypeEntity.derivedIndex(), fieldValue);
         }
 
         // write field 3
         fieldValue.reset();
         aString.setValue(Calendar.getInstance().getTime().toString());
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.DATATYPE_ARECORD_TIMESTAMP_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(datatypeEntity.timestampIndex(), fieldValue);
 
         // write record
         recordBuilder.write(tupleBuilder.getDataOutput(), true);
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/DataverseTupleTranslator.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/DataverseTupleTranslator.java
index 77c838a..8764054 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/DataverseTupleTranslator.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/DataverseTupleTranslator.java
@@ -22,8 +22,7 @@
 import java.util.Calendar;
 
 import org.apache.asterix.common.metadata.DataverseName;
-import org.apache.asterix.metadata.bootstrap.MetadataPrimaryIndexes;
-import org.apache.asterix.metadata.bootstrap.MetadataRecordTypes;
+import org.apache.asterix.metadata.bootstrap.DataverseEntity;
 import org.apache.asterix.metadata.entities.Dataverse;
 import org.apache.asterix.om.base.AInt32;
 import org.apache.asterix.om.base.AMutableInt32;
@@ -38,13 +37,12 @@
  */
 public class DataverseTupleTranslator extends AbstractTupleTranslator<Dataverse> {
 
-    // Payload field containing serialized Dataverse.
-    private static final int DATAVERSE_PAYLOAD_TUPLE_FIELD_INDEX = 1;
+    private final DataverseEntity dataverseEntity;
+    private AMutableInt32 aInt32;
 
-    protected AMutableInt32 aInt32;
-
-    protected DataverseTupleTranslator(boolean getTuple) {
-        super(getTuple, MetadataPrimaryIndexes.DATAVERSE_DATASET, DATAVERSE_PAYLOAD_TUPLE_FIELD_INDEX);
+    protected DataverseTupleTranslator(boolean getTuple, DataverseEntity dataverseEntity) {
+        super(getTuple, dataverseEntity.getIndex(), dataverseEntity.payloadPosition());
+        this.dataverseEntity = dataverseEntity;
         if (getTuple) {
             aInt32 = new AMutableInt32(-1);
         }
@@ -52,10 +50,11 @@
 
     @Override
     protected Dataverse createMetadataEntityFromARecord(ARecord dataverseRecord) throws AlgebricksException {
-        String dataverseCanonicalName = ((AString) dataverseRecord.getValueByPos(0)).getStringValue();
+        String dataverseCanonicalName =
+                ((AString) dataverseRecord.getValueByPos(dataverseEntity.dataverseNameIndex())).getStringValue();
         DataverseName dataverseName = DataverseName.createFromCanonicalForm(dataverseCanonicalName);
-        String format = ((AString) dataverseRecord.getValueByPos(1)).getStringValue();
-        int pendingOp = ((AInt32) dataverseRecord.getValueByPos(3)).getIntegerValue();
+        String format = ((AString) dataverseRecord.getValueByPos(dataverseEntity.dataFormatIndex())).getStringValue();
+        int pendingOp = ((AInt32) dataverseRecord.getValueByPos(dataverseEntity.pendingOpIndex())).getIntegerValue();
 
         return new Dataverse(dataverseName, format, pendingOp);
     }
@@ -71,30 +70,30 @@
         tupleBuilder.addFieldEndOffset();
 
         // write the payload in the second field of the tuple
-        recordBuilder.reset(MetadataRecordTypes.DATAVERSE_RECORDTYPE);
+        recordBuilder.reset(dataverseEntity.getRecordType());
         // write field 0
         fieldValue.reset();
         aString.setValue(dataverseCanonicalName);
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.DATAVERSE_ARECORD_NAME_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(dataverseEntity.dataverseNameIndex(), fieldValue);
 
         // write field 1
         fieldValue.reset();
         aString.setValue(dataverse.getDataFormat());
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.DATAVERSE_ARECORD_FORMAT_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(dataverseEntity.dataFormatIndex(), fieldValue);
 
         // write field 2
         fieldValue.reset();
         aString.setValue(Calendar.getInstance().getTime().toString());
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.DATAVERSE_ARECORD_TIMESTAMP_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(dataverseEntity.timestampIndex(), fieldValue);
 
         // write field 3
         fieldValue.reset();
         aInt32.setValue(dataverse.getPendingOp());
         int32Serde.serialize(aInt32, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.DATAVERSE_ARECORD_PENDINGOP_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(dataverseEntity.pendingOpIndex(), fieldValue);
 
         // write record
         recordBuilder.write(tupleBuilder.getDataOutput(), true);
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/ExternalFileTupleTranslator.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/ExternalFileTupleTranslator.java
index 8c3cacf..21cf462 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/ExternalFileTupleTranslator.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/ExternalFileTupleTranslator.java
@@ -24,8 +24,7 @@
 import org.apache.asterix.common.metadata.DataverseName;
 import org.apache.asterix.external.indexing.ExternalFile;
 import org.apache.asterix.formats.nontagged.SerializerDeserializerProvider;
-import org.apache.asterix.metadata.bootstrap.MetadataPrimaryIndexes;
-import org.apache.asterix.metadata.bootstrap.MetadataRecordTypes;
+import org.apache.asterix.metadata.bootstrap.ExternalFileEntity;
 import org.apache.asterix.om.base.ADateTime;
 import org.apache.asterix.om.base.AInt32;
 import org.apache.asterix.om.base.AInt64;
@@ -42,17 +41,16 @@
 
 public class ExternalFileTupleTranslator extends AbstractTupleTranslator<ExternalFile> {
 
-    // Payload field containing serialized ExternalFile.
-    private static final int EXTERNAL_FILE_PAYLOAD_TUPLE_FIELD_INDEX = 3;
-
+    private final ExternalFileEntity externalFileEntity;
     protected AMutableInt32 aInt32;
     protected AMutableInt64 aInt64;
     protected AMutableDateTime aDateTime;
     protected ISerializerDeserializer<ADateTime> dateTimeSerde;
 
     @SuppressWarnings("unchecked")
-    protected ExternalFileTupleTranslator(boolean getTuple) {
-        super(getTuple, MetadataPrimaryIndexes.EXTERNAL_FILE_DATASET, EXTERNAL_FILE_PAYLOAD_TUPLE_FIELD_INDEX);
+    protected ExternalFileTupleTranslator(boolean getTuple, ExternalFileEntity externalFileEntity) {
+        super(getTuple, externalFileEntity.getIndex(), externalFileEntity.payloadPosition());
+        this.externalFileEntity = externalFileEntity;
         if (getTuple) {
             aInt32 = new AMutableInt32(0);
             aInt64 = new AMutableInt64(0);
@@ -63,21 +61,20 @@
 
     @Override
     protected ExternalFile createMetadataEntityFromARecord(ARecord externalFileRecord) throws AlgebricksException {
-        String dataverseCanonicalName = ((AString) externalFileRecord
-                .getValueByPos(MetadataRecordTypes.EXTERNAL_FILE_ARECORD_DATAVERSENAME_FIELD_INDEX)).getStringValue();
+        String dataverseCanonicalName =
+                ((AString) externalFileRecord.getValueByPos(externalFileEntity.dataverseNameIndex())).getStringValue();
         DataverseName dataverseName = DataverseName.createFromCanonicalForm(dataverseCanonicalName);
-        String datasetName = ((AString) externalFileRecord
-                .getValueByPos(MetadataRecordTypes.EXTERNAL_FILE_ARECORD_DATASET_NAME_FIELD_INDEX)).getStringValue();
-        int fileNumber = ((AInt32) externalFileRecord
-                .getValueByPos(MetadataRecordTypes.EXTERNAL_FILE_ARECORD_FILE_NUMBER_FIELD_INDEX)).getIntegerValue();
-        String fileName = ((AString) externalFileRecord
-                .getValueByPos(MetadataRecordTypes.EXTERNAL_FILE_ARECORD_FILE_NAME_FIELD_INDEX)).getStringValue();
-        long fileSize = ((AInt64) externalFileRecord
-                .getValueByPos(MetadataRecordTypes.EXTERNAL_FILE_ARECORD_FILE_SIZE_FIELD_INDEX)).getLongValue();
-        Date lastMoDifiedDate = new Date(((ADateTime) externalFileRecord
-                .getValueByPos(MetadataRecordTypes.EXTERNAL_FILE_ARECORD_FILE_MOD_DATE_FIELD_INDEX)).getChrononTime());
-        ExternalFilePendingOp pendingOp = ExternalFilePendingOp.values()[((AInt32) externalFileRecord
-                .getValueByPos(MetadataRecordTypes.EXTERNAL_FILE_ARECORD_FILE_PENDING_OP_FIELD_INDEX))
+        String datasetName =
+                ((AString) externalFileRecord.getValueByPos(externalFileEntity.datasetNameIndex())).getStringValue();
+        int fileNumber =
+                ((AInt32) externalFileRecord.getValueByPos(externalFileEntity.fileNumberIndex())).getIntegerValue();
+        String fileName =
+                ((AString) externalFileRecord.getValueByPos(externalFileEntity.fileNameIndex())).getStringValue();
+        long fileSize = ((AInt64) externalFileRecord.getValueByPos(externalFileEntity.fileSizeIndex())).getLongValue();
+        Date lastMoDifiedDate = new Date(
+                ((ADateTime) externalFileRecord.getValueByPos(externalFileEntity.fileModDateIndex())).getChrononTime());
+        ExternalFilePendingOp pendingOp = ExternalFilePendingOp
+                .values()[((AInt32) externalFileRecord.getValueByPos(externalFileEntity.pendingOpIndex()))
                         .getIntegerValue()];
         return new ExternalFile(dataverseName, datasetName, fileNumber, fileName, lastMoDifiedDate, fileSize,
                 pendingOp);
@@ -103,49 +100,49 @@
         tupleBuilder.addFieldEndOffset();
 
         // write the pay-load in the fourth field of the tuple
-        recordBuilder.reset(MetadataRecordTypes.EXTERNAL_FILE_RECORDTYPE);
+        recordBuilder.reset(externalFileEntity.getRecordType());
 
         // write field 0
         fieldValue.reset();
         aString.setValue(dataverseCanonicalName);
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.EXTERNAL_FILE_ARECORD_DATAVERSENAME_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(externalFileEntity.dataverseNameIndex(), fieldValue);
 
         // write field 1
         fieldValue.reset();
         aString.setValue(externalFile.getDatasetName());
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.EXTERNAL_FILE_ARECORD_DATASET_NAME_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(externalFileEntity.datasetNameIndex(), fieldValue);
 
         // write field 2
         fieldValue.reset();
         aInt32.setValue(externalFile.getFileNumber());
         int32Serde.serialize(aInt32, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.EXTERNAL_FILE_ARECORD_FILE_NUMBER_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(externalFileEntity.fileNumberIndex(), fieldValue);
 
         // write field 3
         fieldValue.reset();
         aString.setValue(externalFile.getFileName());
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.EXTERNAL_FILE_ARECORD_FILE_NAME_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(externalFileEntity.fileNameIndex(), fieldValue);
 
         // write field 4
         fieldValue.reset();
         aInt64.setValue(externalFile.getSize());
         int64Serde.serialize(aInt64, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.EXTERNAL_FILE_ARECORD_FILE_SIZE_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(externalFileEntity.fileSizeIndex(), fieldValue);
 
         // write field 5
         fieldValue.reset();
         aDateTime.setValue(externalFile.getLastModefiedTime().getTime());
         dateTimeSerde.serialize(aDateTime, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.EXTERNAL_FILE_ARECORD_FILE_MOD_DATE_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(externalFileEntity.fileModDateIndex(), fieldValue);
 
         // write field 6
         fieldValue.reset();
         aInt32.setValue(externalFile.getPendingOp().ordinal());
         int32Serde.serialize(aInt32, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.EXTERNAL_FILE_ARECORD_FILE_PENDING_OP_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(externalFileEntity.pendingOpIndex(), fieldValue);
 
         // write record
         recordBuilder.write(tupleBuilder.getDataOutput(), true);
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/FeedConnectionTupleTranslator.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/FeedConnectionTupleTranslator.java
index 11b4cea..bef6937 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/FeedConnectionTupleTranslator.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/FeedConnectionTupleTranslator.java
@@ -26,7 +26,7 @@
 import org.apache.asterix.builders.UnorderedListBuilder;
 import org.apache.asterix.common.functions.FunctionSignature;
 import org.apache.asterix.common.metadata.DataverseName;
-import org.apache.asterix.metadata.bootstrap.MetadataPrimaryIndexes;
+import org.apache.asterix.metadata.bootstrap.FeedConnectionEntity;
 import org.apache.asterix.metadata.bootstrap.MetadataRecordTypes;
 import org.apache.asterix.metadata.entities.FeedConnection;
 import org.apache.asterix.om.base.AMissing;
@@ -43,39 +43,35 @@
 
 public class FeedConnectionTupleTranslator extends AbstractTupleTranslator<FeedConnection> {
 
-    // Payload field containing serialized ExternalFile.
-    private static final int FEED_CONNECTION_PAYLOAD_TUPLE_FIELD_INDEX = 3;
+    private final FeedConnectionEntity feedConnectionEntity;
 
-    public FeedConnectionTupleTranslator(boolean getTuple) {
-        super(getTuple, MetadataPrimaryIndexes.FEED_CONNECTION_DATASET, FEED_CONNECTION_PAYLOAD_TUPLE_FIELD_INDEX);
+    public FeedConnectionTupleTranslator(boolean getTuple, FeedConnectionEntity feedConnectionEntity) {
+        super(getTuple, feedConnectionEntity.getIndex(), feedConnectionEntity.payloadPosition());
+        this.feedConnectionEntity = feedConnectionEntity;
     }
 
     @Override
     protected FeedConnection createMetadataEntityFromARecord(ARecord feedConnectionRecord) throws AlgebricksException {
         String dataverseCanonicalName =
-                ((AString) feedConnectionRecord.getValueByPos(MetadataRecordTypes.FEED_CONN_DATAVERSE_NAME_FIELD_INDEX))
+                ((AString) feedConnectionRecord.getValueByPos(feedConnectionEntity.dataverseNameIndex()))
                         .getStringValue();
         DataverseName dataverseName = DataverseName.createFromCanonicalForm(dataverseCanonicalName);
         String feedName =
-                ((AString) feedConnectionRecord.getValueByPos(MetadataRecordTypes.FEED_CONN_FEED_NAME_FIELD_INDEX))
-                        .getStringValue();
-        String datasetName =
-                ((AString) feedConnectionRecord.getValueByPos(MetadataRecordTypes.FEED_CONN_DATASET_NAME_FIELD_INDEX))
-                        .getStringValue();
+                ((AString) feedConnectionRecord.getValueByPos(feedConnectionEntity.feedNameIndex())).getStringValue();
+        String datasetName = ((AString) feedConnectionRecord.getValueByPos(feedConnectionEntity.datasetNameIndex()))
+                .getStringValue();
         String outputType =
-                ((AString) feedConnectionRecord.getValueByPos(MetadataRecordTypes.FEED_CONN_OUTPUT_TYPE_INDEX))
-                        .getStringValue();
+                ((AString) feedConnectionRecord.getValueByPos(feedConnectionEntity.outputTypeIndex())).getStringValue();
         String policyName =
-                ((AString) feedConnectionRecord.getValueByPos(MetadataRecordTypes.FEED_CONN_POLICY_FIELD_INDEX))
-                        .getStringValue();
+                ((AString) feedConnectionRecord.getValueByPos(feedConnectionEntity.policyIndex())).getStringValue();
         List<FunctionSignature> appliedFunctions = null;
-        Object o = feedConnectionRecord.getValueByPos(MetadataRecordTypes.FEED_CONN_APPLIED_FUNCTIONS_FIELD_INDEX);
+        Object o = feedConnectionRecord.getValueByPos(feedConnectionEntity.appliedFunctionsIndex());
         IACursor cursor;
 
         if (!(o instanceof ANull) && !(o instanceof AMissing)) {
             appliedFunctions = new ArrayList<>();
-            AUnorderedList afList = (AUnorderedList) feedConnectionRecord
-                    .getValueByPos(MetadataRecordTypes.FEED_CONN_APPLIED_FUNCTIONS_FIELD_INDEX);
+            AUnorderedList afList =
+                    (AUnorderedList) feedConnectionRecord.getValueByPos(feedConnectionEntity.appliedFunctionsIndex());
             cursor = afList.getCursor();
             while (cursor.next()) {
                 String afValue = ((AString) cursor.get()).getStringValue();
@@ -117,31 +113,31 @@
         stringSerde.serialize(aString, tupleBuilder.getDataOutput());
         tupleBuilder.addFieldEndOffset();
 
-        recordBuilder.reset(MetadataRecordTypes.FEED_CONNECTION_RECORDTYPE);
+        recordBuilder.reset(feedConnectionEntity.getRecordType());
 
         // field dataverse
         fieldValue.reset();
         aString.setValue(dataverseCanonicalName);
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.FEED_CONN_DATAVERSE_NAME_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(feedConnectionEntity.dataverseNameIndex(), fieldValue);
 
         // field: feedId
         fieldValue.reset();
         aString.setValue(feedConnection.getFeedName());
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.FEED_CONN_FEED_NAME_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(feedConnectionEntity.feedNameIndex(), fieldValue);
 
         // field: dataset
         fieldValue.reset();
         aString.setValue(feedConnection.getDatasetName());
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.FEED_CONN_DATASET_NAME_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(feedConnectionEntity.datasetNameIndex(), fieldValue);
 
         // field: outputType
         fieldValue.reset();
         aString.setValue(feedConnection.getOutputType());
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.FEED_CONN_OUTPUT_TYPE_INDEX, fieldValue);
+        recordBuilder.addField(feedConnectionEntity.outputTypeIndex(), fieldValue);
 
         // field: appliedFunctions
         fieldValue.reset();
@@ -151,7 +147,7 @@
         fieldValue.reset();
         aString.setValue(feedConnection.getPolicyName());
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.FEED_CONN_POLICY_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(feedConnectionEntity.policyIndex(), fieldValue);
 
         // write open fields
         writeOpenFields(feedConnection);
@@ -185,8 +181,8 @@
         UnorderedListBuilder listBuilder = new UnorderedListBuilder();
         ArrayBackedValueStorage listEleBuffer = new ArrayBackedValueStorage();
 
-        listBuilder.reset((AUnorderedListType) MetadataRecordTypes.FEED_CONNECTION_RECORDTYPE
-                .getFieldTypes()[MetadataRecordTypes.FEED_CONN_APPLIED_FUNCTIONS_FIELD_INDEX]);
+        listBuilder.reset((AUnorderedListType) feedConnectionEntity.getRecordType().getFieldTypes()[feedConnectionEntity
+                .appliedFunctionsIndex()]);
         if (fc.getAppliedFunctions() != null) {
             List<FunctionSignature> appliedFunctions = fc.getAppliedFunctions();
             for (FunctionSignature af : appliedFunctions) {
@@ -197,6 +193,6 @@
             }
         }
         listBuilder.write(buffer.getDataOutput(), true);
-        rb.addField(MetadataRecordTypes.FEED_CONN_APPLIED_FUNCTIONS_FIELD_INDEX, buffer);
+        rb.addField(feedConnectionEntity.appliedFunctionsIndex(), buffer);
     }
 }
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/FeedPolicyTupleTranslator.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/FeedPolicyTupleTranslator.java
index 9ffe5dc..edfa69f 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/FeedPolicyTupleTranslator.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/FeedPolicyTupleTranslator.java
@@ -27,7 +27,6 @@
 import org.apache.asterix.builders.RecordBuilder;
 import org.apache.asterix.builders.UnorderedListBuilder;
 import org.apache.asterix.common.metadata.DataverseName;
-import org.apache.asterix.metadata.bootstrap.MetadataPrimaryIndexes;
 import org.apache.asterix.metadata.bootstrap.MetadataRecordTypes;
 import org.apache.asterix.metadata.entities.FeedPolicyEntity;
 import org.apache.asterix.om.base.AMutableString;
@@ -46,25 +45,26 @@
  */
 public class FeedPolicyTupleTranslator extends AbstractTupleTranslator<FeedPolicyEntity> {
 
-    // Payload field containing serialized feedPolicy.
-    private static final int FEED_POLICY_PAYLOAD_TUPLE_FIELD_INDEX = 2;
+    private final org.apache.asterix.metadata.bootstrap.FeedPolicyEntity feedPolicyEntity;
 
-    protected FeedPolicyTupleTranslator(boolean getTuple) {
-        super(getTuple, MetadataPrimaryIndexes.FEED_POLICY_DATASET, FEED_POLICY_PAYLOAD_TUPLE_FIELD_INDEX);
+    protected FeedPolicyTupleTranslator(boolean getTuple,
+            org.apache.asterix.metadata.bootstrap.FeedPolicyEntity feedPolicyEntity) {
+        super(getTuple, feedPolicyEntity.getIndex(), feedPolicyEntity.payloadPosition());
+        this.feedPolicyEntity = feedPolicyEntity;
     }
 
     @Override
     protected FeedPolicyEntity createMetadataEntityFromARecord(ARecord feedPolicyRecord) throws AlgebricksException {
-        String dataverseCanonicalName = ((AString) feedPolicyRecord
-                .getValueByPos(MetadataRecordTypes.FEED_POLICY_ARECORD_DATAVERSE_NAME_FIELD_INDEX)).getStringValue();
+        String dataverseCanonicalName =
+                ((AString) feedPolicyRecord.getValueByPos(feedPolicyEntity.dataverseNameIndex())).getStringValue();
         DataverseName dataverseName = DataverseName.createFromCanonicalForm(dataverseCanonicalName);
-        String policyName = ((AString) feedPolicyRecord
-                .getValueByPos(MetadataRecordTypes.FEED_POLICY_ARECORD_POLICY_NAME_FIELD_INDEX)).getStringValue();
-        String description = ((AString) feedPolicyRecord
-                .getValueByPos(MetadataRecordTypes.FEED_POLICY_ARECORD_DESCRIPTION_FIELD_INDEX)).getStringValue();
+        String policyName =
+                ((AString) feedPolicyRecord.getValueByPos(feedPolicyEntity.policyNameIndex())).getStringValue();
+        String description =
+                ((AString) feedPolicyRecord.getValueByPos(feedPolicyEntity.descriptionIndex())).getStringValue();
 
-        IACursor cursor = ((AUnorderedList) feedPolicyRecord
-                .getValueByPos(MetadataRecordTypes.FEED_POLICY_ARECORD_PROPERTIES_FIELD_INDEX)).getCursor();
+        IACursor cursor =
+                ((AUnorderedList) feedPolicyRecord.getValueByPos(feedPolicyEntity.propertiesIndex())).getCursor();
         Map<String, String> policyParamters = new HashMap<>();
         while (cursor.next()) {
             ARecord field = (ARecord) cursor.get();
@@ -92,31 +92,31 @@
         stringSerde.serialize(aString, tupleBuilder.getDataOutput());
         tupleBuilder.addFieldEndOffset();
 
-        recordBuilder.reset(MetadataRecordTypes.FEED_POLICY_RECORDTYPE);
+        recordBuilder.reset(feedPolicyEntity.getRecordType());
 
         // write field 0
         fieldValue.reset();
         aString.setValue(dataverseCanonicalName);
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.FEED_POLICY_ARECORD_DATAVERSE_NAME_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(feedPolicyEntity.dataverseNameIndex(), fieldValue);
 
         // write field 1
         fieldValue.reset();
         aString.setValue(feedPolicy.getPolicyName());
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.FEED_POLICY_ARECORD_POLICY_NAME_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(feedPolicyEntity.policyNameIndex(), fieldValue);
 
         // write field 2
         fieldValue.reset();
         aString.setValue(feedPolicy.getDescription());
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.FEED_POLICY_ARECORD_DESCRIPTION_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(feedPolicyEntity.descriptionIndex(), fieldValue);
 
         // write field 3 (properties)
         Map<String, String> properties = feedPolicy.getProperties();
         UnorderedListBuilder listBuilder = new UnorderedListBuilder();
-        listBuilder.reset((AUnorderedListType) MetadataRecordTypes.FEED_POLICY_RECORDTYPE
-                .getFieldTypes()[MetadataRecordTypes.FEED_POLICY_ARECORD_PROPERTIES_FIELD_INDEX]);
+        listBuilder.reset((AUnorderedListType) feedPolicyEntity.getRecordType().getFieldTypes()[feedPolicyEntity
+                .propertiesIndex()]);
         ArrayBackedValueStorage itemValue = new ArrayBackedValueStorage();
         for (Map.Entry<String, String> property : properties.entrySet()) {
             String name = property.getKey();
@@ -127,7 +127,7 @@
         }
         fieldValue.reset();
         listBuilder.write(fieldValue.getDataOutput(), true);
-        recordBuilder.addField(MetadataRecordTypes.FEED_POLICY_ARECORD_PROPERTIES_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(feedPolicyEntity.propertiesIndex(), fieldValue);
 
         // write record
         recordBuilder.write(tupleBuilder.getDataOutput(), true);
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/FeedTupleTranslator.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/FeedTupleTranslator.java
index 8834522..bb1c9ad 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/FeedTupleTranslator.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/FeedTupleTranslator.java
@@ -28,7 +28,7 @@
 import org.apache.asterix.builders.RecordBuilder;
 import org.apache.asterix.builders.UnorderedListBuilder;
 import org.apache.asterix.common.metadata.DataverseName;
-import org.apache.asterix.metadata.bootstrap.MetadataPrimaryIndexes;
+import org.apache.asterix.metadata.bootstrap.FeedEntity;
 import org.apache.asterix.metadata.bootstrap.MetadataRecordTypes;
 import org.apache.asterix.metadata.entities.Feed;
 import org.apache.asterix.om.base.AMutableString;
@@ -47,24 +47,21 @@
  */
 public class FeedTupleTranslator extends AbstractTupleTranslator<Feed> {
 
-    // Payload field containing serialized feed.
-    private static final int FEED_PAYLOAD_TUPLE_FIELD_INDEX = 2;
+    private final FeedEntity feedEntity;
 
-    protected FeedTupleTranslator(boolean getTuple) {
-        super(getTuple, MetadataPrimaryIndexes.FEED_DATASET, FEED_PAYLOAD_TUPLE_FIELD_INDEX);
+    protected FeedTupleTranslator(boolean getTuple, FeedEntity feedEntity) {
+        super(getTuple, feedEntity.getIndex(), feedEntity.payloadPosition());
+        this.feedEntity = feedEntity;
     }
 
     @Override
     protected Feed createMetadataEntityFromARecord(ARecord feedRecord) throws AlgebricksException {
         String dataverseCanonicalName =
-                ((AString) feedRecord.getValueByPos(MetadataRecordTypes.FEED_ARECORD_DATAVERSE_NAME_FIELD_INDEX))
-                        .getStringValue();
+                ((AString) feedRecord.getValueByPos(feedEntity.dataverseNameIndex())).getStringValue();
         DataverseName dataverseName = DataverseName.createFromCanonicalForm(dataverseCanonicalName);
-        String feedName = ((AString) feedRecord.getValueByPos(MetadataRecordTypes.FEED_ARECORD_FEED_NAME_FIELD_INDEX))
-                .getStringValue();
+        String feedName = ((AString) feedRecord.getValueByPos(feedEntity.feedNameIndex())).getStringValue();
 
-        AUnorderedList feedConfig =
-                (AUnorderedList) feedRecord.getValueByPos(MetadataRecordTypes.FEED_ARECORD_ADAPTOR_CONFIG_INDEX);
+        AUnorderedList feedConfig = (AUnorderedList) feedRecord.getValueByPos(feedEntity.adapterConfigIndex());
         IACursor cursor = feedConfig.getCursor();
         // restore configurations
         Map<String, String> adaptorConfiguration = new HashMap<>();
@@ -94,19 +91,19 @@
         stringSerde.serialize(aString, tupleBuilder.getDataOutput());
         tupleBuilder.addFieldEndOffset();
 
-        recordBuilder.reset(MetadataRecordTypes.FEED_RECORDTYPE);
+        recordBuilder.reset(feedEntity.getRecordType());
 
         // write dataverse name
         fieldValue.reset();
         aString.setValue(dataverseCanonicalName);
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.FEED_ARECORD_DATAVERSE_NAME_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(feedEntity.dataverseNameIndex(), fieldValue);
 
         // write feed name
         fieldValue.reset();
         aString.setValue(feed.getFeedName());
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.FEED_ARECORD_FEED_NAME_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(feedEntity.feedNameIndex(), fieldValue);
 
         // write adaptor configuration
         fieldValue.reset();
@@ -116,7 +113,7 @@
         fieldValue.reset();
         aString.setValue(Calendar.getInstance().getTime().toString());
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.FEED_ARECORD_TIMESTAMP_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(feedEntity.timestampIndex(), fieldValue);
 
         // write record
         recordBuilder.write(tupleBuilder.getDataOutput(), true);
@@ -131,8 +128,8 @@
         UnorderedListBuilder listBuilder = new UnorderedListBuilder();
         ArrayBackedValueStorage listEleBuffer = new ArrayBackedValueStorage();
 
-        listBuilder.reset((AUnorderedListType) MetadataRecordTypes.FEED_RECORDTYPE
-                .getFieldTypes()[MetadataRecordTypes.FEED_ARECORD_ADAPTOR_CONFIG_INDEX]);
+        listBuilder.reset(
+                (AUnorderedListType) feedEntity.getRecordType().getFieldTypes()[feedEntity.adapterConfigIndex()]);
         for (Map.Entry<String, String> property : feed.getConfiguration().entrySet()) {
             String name = property.getKey();
             String value = property.getValue();
@@ -141,7 +138,7 @@
             listBuilder.addItem(listEleBuffer);
         }
         listBuilder.write(fieldValueBuffer.getDataOutput(), true);
-        recordBuilder.addField(MetadataRecordTypes.FEED_ARECORD_ADAPTOR_CONFIG_INDEX, fieldValueBuffer);
+        recordBuilder.addField(feedEntity.adapterConfigIndex(), fieldValueBuffer);
     }
 
     private void writePropertyTypeRecord(String name, String value, DataOutput out) throws HyracksDataException {
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/FullTextConfigMetadataEntityTupleTranslator.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/FullTextConfigMetadataEntityTupleTranslator.java
index ec5cdc9..5403f1d 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/FullTextConfigMetadataEntityTupleTranslator.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/FullTextConfigMetadataEntityTupleTranslator.java
@@ -19,20 +19,12 @@
 
 package org.apache.asterix.metadata.entitytupletranslators;
 
-import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FULL_TEXT_ARECORD_CONFIG_NAME_FIELD_INDEX;
-import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FULL_TEXT_ARECORD_CONFIG_TOKENIZER_FIELD_INDEX;
-import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FULL_TEXT_ARECORD_DATAVERSE_NAME_FIELD_INDEX;
-import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FULL_TEXT_ARECORD_FILTER_PIPELINE_FIELD_INDEX;
-
 import java.util.List;
 
 import org.apache.asterix.builders.OrderedListBuilder;
 import org.apache.asterix.common.metadata.DataverseName;
-import org.apache.asterix.formats.nontagged.SerializerDeserializerProvider;
-import org.apache.asterix.metadata.bootstrap.MetadataPrimaryIndexes;
-import org.apache.asterix.metadata.bootstrap.MetadataRecordTypes;
+import org.apache.asterix.metadata.bootstrap.FullTextConfigEntity;
 import org.apache.asterix.metadata.entities.FullTextConfigMetadataEntity;
-import org.apache.asterix.om.base.AInt8;
 import org.apache.asterix.om.base.AOrderedList;
 import org.apache.asterix.om.base.ARecord;
 import org.apache.asterix.om.base.AString;
@@ -42,7 +34,6 @@
 import org.apache.asterix.runtime.fulltext.FullTextConfigDescriptor;
 import org.apache.commons.lang3.EnumUtils;
 import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
-import org.apache.hyracks.api.dataflow.value.ISerializerDeserializer;
 import org.apache.hyracks.api.exceptions.HyracksDataException;
 import org.apache.hyracks.data.std.util.ArrayBackedValueStorage;
 import org.apache.hyracks.dataflow.common.comm.io.ArrayTupleBuilder;
@@ -54,13 +45,12 @@
 
 public class FullTextConfigMetadataEntityTupleTranslator extends AbstractTupleTranslator<FullTextConfigMetadataEntity> {
 
-    private static final int FULL_TEXT_CONFIG_PAYLOAD_TUPLE_FIELD_INDEX = 2;
+    private final FullTextConfigEntity fullTextConfigEntity;
     protected final ArrayTupleReference tuple;
-    protected final ISerializerDeserializer<AInt8> int8Serde =
-            SerializerDeserializerProvider.INSTANCE.getSerializerDeserializer(BuiltinType.AINT8);
 
-    protected FullTextConfigMetadataEntityTupleTranslator(boolean getTuple) {
-        super(getTuple, MetadataPrimaryIndexes.FULL_TEXT_CONFIG_DATASET, FULL_TEXT_CONFIG_PAYLOAD_TUPLE_FIELD_INDEX);
+    protected FullTextConfigMetadataEntityTupleTranslator(boolean getTuple, FullTextConfigEntity fullTextConfigEntity) {
+        super(getTuple, fullTextConfigEntity.getIndex(), fullTextConfigEntity.payloadPosition());
+        this.fullTextConfigEntity = fullTextConfigEntity;
         if (getTuple) {
             tuple = new ArrayTupleReference();
         } else {
@@ -72,29 +62,23 @@
     protected FullTextConfigMetadataEntity createMetadataEntityFromARecord(ARecord aRecord)
             throws HyracksDataException, AlgebricksException {
         DataverseName dataverseName = DataverseName.createFromCanonicalForm(
-                ((AString) aRecord.getValueByPos(MetadataRecordTypes.FULL_TEXT_ARECORD_DATAVERSE_NAME_FIELD_INDEX))
-                        .getStringValue());
+                ((AString) aRecord.getValueByPos(fullTextConfigEntity.dataverseNameIndex())).getStringValue());
 
-        String name = ((AString) aRecord.getValueByPos(MetadataRecordTypes.FULL_TEXT_ARECORD_CONFIG_NAME_FIELD_INDEX))
-                .getStringValue();
+        String name = ((AString) aRecord.getValueByPos(fullTextConfigEntity.configNameIndex())).getStringValue();
 
-        TokenizerCategory tokenizerCategory =
-                EnumUtils.getEnumIgnoreCase(TokenizerCategory.class,
-                        ((AString) aRecord
-                                .getValueByPos(MetadataRecordTypes.FULL_TEXT_ARECORD_CONFIG_TOKENIZER_FIELD_INDEX))
-                                        .getStringValue());
+        TokenizerCategory tokenizerCategory = EnumUtils.getEnumIgnoreCase(TokenizerCategory.class,
+                ((AString) aRecord.getValueByPos(fullTextConfigEntity.tokenizerIndex())).getStringValue());
 
         ImmutableList.Builder<String> filterNamesBuilder = ImmutableList.builder();
-        IACursor filterNamesCursor = ((AOrderedList) (aRecord
-                .getValueByPos(MetadataRecordTypes.FULL_TEXT_ARECORD_FILTER_PIPELINE_FIELD_INDEX))).getCursor();
+        IACursor filterNamesCursor =
+                ((AOrderedList) (aRecord.getValueByPos(fullTextConfigEntity.filterPipelineIndex()))).getCursor();
         while (filterNamesCursor.next()) {
             filterNamesBuilder.add(((AString) filterNamesCursor.get()).getStringValue());
         }
 
         FullTextConfigDescriptor configDescriptor =
                 new FullTextConfigDescriptor(dataverseName, name, tokenizerCategory, filterNamesBuilder.build());
-        FullTextConfigMetadataEntity configMetadataEntity = new FullTextConfigMetadataEntity(configDescriptor);
-        return configMetadataEntity;
+        return new FullTextConfigMetadataEntity(configDescriptor);
     }
 
     private void writeIndex(String dataverseName, String configName, ArrayTupleBuilder tupleBuilder)
@@ -117,25 +101,25 @@
 
         writeIndex(configDescriptor.getDataverseName().getCanonicalForm(), configDescriptor.getName(), tupleBuilder);
 
-        recordBuilder.reset(MetadataRecordTypes.FULL_TEXT_CONFIG_RECORDTYPE);
+        recordBuilder.reset(fullTextConfigEntity.getRecordType());
 
         // write dataverse name
         fieldValue.reset();
         aString.setValue(configDescriptor.getDataverseName().getCanonicalForm());
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(FULL_TEXT_ARECORD_DATAVERSE_NAME_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(fullTextConfigEntity.dataverseNameIndex(), fieldValue);
 
         // write name
         fieldValue.reset();
         aString.setValue(configDescriptor.getName());
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(FULL_TEXT_ARECORD_CONFIG_NAME_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(fullTextConfigEntity.configNameIndex(), fieldValue);
 
         // write tokenizer category
         fieldValue.reset();
         aString.setValue(configDescriptor.getTokenizerCategory().name());
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(FULL_TEXT_ARECORD_CONFIG_TOKENIZER_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(fullTextConfigEntity.tokenizerIndex(), fieldValue);
 
         // set filter pipeline
         List<String> filterNames = configDescriptor.getFilterNames();
@@ -152,7 +136,7 @@
 
         fieldValue.reset();
         listBuilder.write(fieldValue.getDataOutput(), true);
-        recordBuilder.addField(FULL_TEXT_ARECORD_FILTER_PIPELINE_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(fullTextConfigEntity.filterPipelineIndex(), fieldValue);
 
         recordBuilder.write(tupleBuilder.getDataOutput(), true);
         tupleBuilder.addFieldEndOffset();
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/FullTextFilterMetadataEntityTupleTranslator.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/FullTextFilterMetadataEntityTupleTranslator.java
index 2212e82..7d66f3b 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/FullTextFilterMetadataEntityTupleTranslator.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/FullTextFilterMetadataEntityTupleTranslator.java
@@ -20,9 +20,6 @@
 package org.apache.asterix.metadata.entitytupletranslators;
 
 import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_FULL_TEXT_STOPWORD_LIST;
-import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FULL_TEXT_ARECORD_DATAVERSE_NAME_FIELD_INDEX;
-import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FULL_TEXT_ARECORD_FILTER_NAME_FIELD_INDEX;
-import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FULL_TEXT_ARECORD_FILTER_TYPE_FIELD_INDEX;
 
 import java.util.List;
 
@@ -30,11 +27,8 @@
 import org.apache.asterix.common.exceptions.AsterixException;
 import org.apache.asterix.common.exceptions.ErrorCode;
 import org.apache.asterix.common.metadata.DataverseName;
-import org.apache.asterix.formats.nontagged.SerializerDeserializerProvider;
-import org.apache.asterix.metadata.bootstrap.MetadataPrimaryIndexes;
-import org.apache.asterix.metadata.bootstrap.MetadataRecordTypes;
+import org.apache.asterix.metadata.bootstrap.FullTextFilterEntity;
 import org.apache.asterix.metadata.entities.FullTextFilterMetadataEntity;
-import org.apache.asterix.om.base.AInt8;
 import org.apache.asterix.om.base.AOrderedList;
 import org.apache.asterix.om.base.ARecord;
 import org.apache.asterix.om.base.AString;
@@ -44,7 +38,6 @@
 import org.apache.asterix.runtime.fulltext.AbstractFullTextFilterDescriptor;
 import org.apache.asterix.runtime.fulltext.StopwordsFullTextFilterDescriptor;
 import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
-import org.apache.hyracks.api.dataflow.value.ISerializerDeserializer;
 import org.apache.hyracks.api.exceptions.HyracksDataException;
 import org.apache.hyracks.data.std.util.ArrayBackedValueStorage;
 import org.apache.hyracks.dataflow.common.comm.io.ArrayTupleBuilder;
@@ -56,13 +49,12 @@
 
 public class FullTextFilterMetadataEntityTupleTranslator extends AbstractTupleTranslator<FullTextFilterMetadataEntity> {
 
-    private static final int FULLTEXT_FILTER_PAYLOAD_TUPLE_FIELD_INDEX = 2;
+    private final FullTextFilterEntity fullTextFilterEntity;
     protected final ArrayTupleReference tuple;
-    protected final ISerializerDeserializer<AInt8> int8Serde =
-            SerializerDeserializerProvider.INSTANCE.getSerializerDeserializer(BuiltinType.AINT8);
 
-    protected FullTextFilterMetadataEntityTupleTranslator(boolean getTuple) {
-        super(getTuple, MetadataPrimaryIndexes.FULL_TEXT_FILTER_DATASET, FULLTEXT_FILTER_PAYLOAD_TUPLE_FIELD_INDEX);
+    protected FullTextFilterMetadataEntityTupleTranslator(boolean getTuple, FullTextFilterEntity fullTextFilterEntity) {
+        super(getTuple, fullTextFilterEntity.getIndex(), fullTextFilterEntity.payloadPosition());
+        this.fullTextFilterEntity = fullTextFilterEntity;
         if (getTuple) {
             tuple = new ArrayTupleReference();
         } else {
@@ -72,12 +64,11 @@
 
     @Override
     protected FullTextFilterMetadataEntity createMetadataEntityFromARecord(ARecord aRecord) throws AlgebricksException {
-        AString dataverseName = (AString) aRecord.getValueByPos(FULL_TEXT_ARECORD_DATAVERSE_NAME_FIELD_INDEX);
-        AString filterName = (AString) aRecord.getValueByPos(FULL_TEXT_ARECORD_FILTER_NAME_FIELD_INDEX);
-        AString filterTypeAString = (AString) aRecord.getValueByPos(FULL_TEXT_ARECORD_FILTER_TYPE_FIELD_INDEX);
+        AString dataverseName = (AString) aRecord.getValueByPos(fullTextFilterEntity.dataverseNameIndex());
+        AString filterName = (AString) aRecord.getValueByPos(fullTextFilterEntity.filterNameIndex());
+        AString filterTypeAString = (AString) aRecord.getValueByPos(fullTextFilterEntity.filterTypeIndex());
 
         FullTextFilterType filterType = FullTextFilterType.getEnumIgnoreCase(filterTypeAString.getStringValue());
-        AbstractFullTextFilterDescriptor filterDescriptor;
         switch (filterType) {
             case STOPWORDS:
                 return createStopwordsFilterDescriptorFromARecord(dataverseName, filterName, aRecord);
@@ -91,10 +82,12 @@
     public FullTextFilterMetadataEntity createStopwordsFilterDescriptorFromARecord(AString dataverseName, AString name,
             ARecord aRecord) throws AlgebricksException {
         ImmutableList.Builder<String> stopwordsBuilder = ImmutableList.<String> builder();
-        IACursor stopwordsCursor = ((AOrderedList) (aRecord
-                .getValueByPos(MetadataRecordTypes.FULLTEXT_ENTITY_ARECORD_STOPWORD_LIST_FIELD_INDEX))).getCursor();
-        while (stopwordsCursor.next()) {
-            stopwordsBuilder.add(((AString) stopwordsCursor.get()).getStringValue());
+        int fieldIndex = aRecord.getType().getFieldIndex(FIELD_NAME_FULL_TEXT_STOPWORD_LIST);
+        if (fieldIndex >= 0) {
+            IACursor stopwordsCursor = ((AOrderedList) (aRecord.getValueByPos(fieldIndex))).getCursor();
+            while (stopwordsCursor.next()) {
+                stopwordsBuilder.add(((AString) stopwordsCursor.get()).getStringValue());
+            }
         }
 
         StopwordsFullTextFilterDescriptor filterDescriptor = new StopwordsFullTextFilterDescriptor(
@@ -145,17 +138,17 @@
         fieldValue.reset();
         aString.setValue(filterDescriptor.getDataverseName().getCanonicalForm());
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(FULL_TEXT_ARECORD_DATAVERSE_NAME_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(fullTextFilterEntity.dataverseNameIndex(), fieldValue);
 
         fieldValue.reset();
         aString.setValue(filterDescriptor.getName());
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(FULL_TEXT_ARECORD_FILTER_NAME_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(fullTextFilterEntity.filterNameIndex(), fieldValue);
 
         fieldValue.reset();
         aString.setValue(filterDescriptor.getFilterType().getValue());
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(FULL_TEXT_ARECORD_FILTER_TYPE_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(fullTextFilterEntity.filterTypeIndex(), fieldValue);
 
         switch (filterDescriptor.getFilterType()) {
             case STOPWORDS:
@@ -188,7 +181,7 @@
                 filterMetadataEntity.getFullTextFilter().getName(), tupleBuilder);
 
         // Write the record
-        recordBuilder.reset(MetadataRecordTypes.FULL_TEXT_FILTER_RECORDTYPE);
+        recordBuilder.reset(fullTextFilterEntity.getRecordType());
 
         writeFulltextFilter(filterMetadataEntity.getFullTextFilter());
 
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/FunctionTupleTranslator.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/FunctionTupleTranslator.java
index 3a5217b..3f61115 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/FunctionTupleTranslator.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/FunctionTupleTranslator.java
@@ -53,7 +53,7 @@
 import org.apache.asterix.common.metadata.DataverseName;
 import org.apache.asterix.common.transactions.TxnId;
 import org.apache.asterix.metadata.MetadataNode;
-import org.apache.asterix.metadata.bootstrap.MetadataPrimaryIndexes;
+import org.apache.asterix.metadata.bootstrap.FunctionEntity;
 import org.apache.asterix.metadata.bootstrap.MetadataRecordTypes;
 import org.apache.asterix.metadata.entities.Function;
 import org.apache.asterix.om.base.ABoolean;
@@ -80,9 +80,7 @@
  */
 public class FunctionTupleTranslator extends AbstractDatatypeTupleTranslator<Function> {
 
-    // Payload field containing serialized Function.
-    private static final int FUNCTION_PAYLOAD_TUPLE_FIELD_INDEX = 3;
-
+    private final FunctionEntity functionEntity;
     protected OrderedListBuilder dependenciesListBuilder;
     protected OrderedListBuilder dependencyListBuilder;
     protected OrderedListBuilder dependencyNameListBuilder;
@@ -90,9 +88,10 @@
     protected AOrderedListType stringList;
     protected AOrderedListType listOfLists;
 
-    protected FunctionTupleTranslator(TxnId txnId, MetadataNode metadataNode, boolean getTuple) {
-        super(txnId, metadataNode, getTuple, MetadataPrimaryIndexes.FUNCTION_DATASET,
-                FUNCTION_PAYLOAD_TUPLE_FIELD_INDEX);
+    protected FunctionTupleTranslator(TxnId txnId, MetadataNode metadataNode, boolean getTuple,
+            FunctionEntity functionEntity) {
+        super(txnId, metadataNode, getTuple, functionEntity.getIndex(), functionEntity.payloadPosition());
+        this.functionEntity = functionEntity;
         if (getTuple) {
             dependenciesListBuilder = new OrderedListBuilder();
             dependencyListBuilder = new OrderedListBuilder();
@@ -105,17 +104,15 @@
 
     protected Function createMetadataEntityFromARecord(ARecord functionRecord) throws AlgebricksException {
         String dataverseCanonicalName =
-                ((AString) functionRecord.getValueByPos(MetadataRecordTypes.FUNCTION_ARECORD_DATAVERSENAME_FIELD_INDEX))
-                        .getStringValue();
+                ((AString) functionRecord.getValueByPos(functionEntity.dataverseNameIndex())).getStringValue();
         DataverseName dataverseName = DataverseName.createFromCanonicalForm(dataverseCanonicalName);
         String functionName =
-                ((AString) functionRecord.getValueByPos(MetadataRecordTypes.FUNCTION_ARECORD_FUNCTIONNAME_FIELD_INDEX))
-                        .getStringValue();
-        int arity = Integer.parseInt(((AString) functionRecord
-                .getValueByPos(MetadataRecordTypes.FUNCTION_ARECORD_FUNCTION_ARITY_FIELD_INDEX)).getStringValue());
+                ((AString) functionRecord.getValueByPos(functionEntity.functionNameIndex())).getStringValue();
+        int arity = Integer.parseInt(
+                ((AString) functionRecord.getValueByPos(functionEntity.functionArityIndex())).getStringValue());
 
-        IACursor paramNameCursor = ((AOrderedList) functionRecord
-                .getValueByPos(MetadataRecordTypes.FUNCTION_ARECORD_FUNCTION_PARAM_LIST_FIELD_INDEX)).getCursor();
+        IACursor paramNameCursor =
+                ((AOrderedList) functionRecord.getValueByPos(functionEntity.functionParamListIndex())).getCursor();
         List<String> paramNames = new ArrayList<>();
         while (paramNameCursor.next()) {
             paramNames.add(((AString) paramNameCursor.get()).getStringValue());
@@ -124,8 +121,8 @@
         List<TypeSignature> paramTypes = getParamTypes(functionRecord, dataverseName);
 
         TypeSignature returnType;
-        String returnTypeName = ((AString) functionRecord
-                .getValueByPos(MetadataRecordTypes.FUNCTION_ARECORD_FUNCTION_RETURN_TYPE_FIELD_INDEX)).getStringValue();
+        String returnTypeName =
+                ((AString) functionRecord.getValueByPos(functionEntity.functionReturnTypeIndex())).getStringValue();
         if (returnTypeName.isEmpty()) {
             returnType = null; // == any
         } else {
@@ -133,13 +130,12 @@
             returnType = getTypeSignature(returnTypeName, returnTypeDataverseNameCanonical, dataverseName);
         }
 
-        String definition = ((AString) functionRecord
-                .getValueByPos(MetadataRecordTypes.FUNCTION_ARECORD_FUNCTION_DEFINITION_FIELD_INDEX)).getStringValue();
-        String language = ((AString) functionRecord
-                .getValueByPos(MetadataRecordTypes.FUNCTION_ARECORD_FUNCTION_LANGUAGE_FIELD_INDEX)).getStringValue();
+        String definition =
+                ((AString) functionRecord.getValueByPos(functionEntity.functionDefinitionIndex())).getStringValue();
+        String language =
+                ((AString) functionRecord.getValueByPos(functionEntity.functionLanguageIndex())).getStringValue();
         String functionKind =
-                ((AString) functionRecord.getValueByPos(MetadataRecordTypes.FUNCTION_ARECORD_FUNCTION_KIND_FIELD_INDEX))
-                        .getStringValue();
+                ((AString) functionRecord.getValueByPos(functionEntity.functionKindIndex())).getStringValue();
 
         Map<String, String> resources = null;
         DataverseName libraryDataverseName = null;
@@ -176,8 +172,8 @@
             deterministic = getBoolean(functionRecord, FUNCTION_ARECORD_FUNCTION_DETERMINISTIC_FIELD_NAME);
         }
 
-        IACursor dependenciesCursor = ((AOrderedList) functionRecord
-                .getValueByPos(MetadataRecordTypes.FUNCTION_ARECORD_FUNCTION_DEPENDENCIES_FIELD_INDEX)).getCursor();
+        IACursor dependenciesCursor =
+                ((AOrderedList) functionRecord.getValueByPos(functionEntity.functionDependenciesIndex())).getCursor();
         List<List<Triple<DataverseName, String, String>>> dependencies = new ArrayList<>();
         while (dependenciesCursor.next()) {
             List<Triple<DataverseName, String, String>> dependencyList = new ArrayList<>();
@@ -301,31 +297,31 @@
 
         // write the pay-load in the fourth field of the tuple
 
-        recordBuilder.reset(MetadataRecordTypes.FUNCTION_RECORDTYPE);
+        recordBuilder.reset(functionEntity.getRecordType());
 
         // write field 0
         fieldValue.reset();
         aString.setValue(dataverseCanonicalName);
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.FUNCTION_ARECORD_DATAVERSENAME_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(functionEntity.dataverseNameIndex(), fieldValue);
 
         // write field 1
         fieldValue.reset();
         aString.setValue(function.getName());
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.FUNCTION_ARECORD_FUNCTIONNAME_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(functionEntity.functionNameIndex(), fieldValue);
 
         // write field 2
         fieldValue.reset();
         aString.setValue(String.valueOf(function.getArity()));
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.FUNCTION_ARECORD_FUNCTION_ARITY_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(functionEntity.functionArityIndex(), fieldValue);
 
         // write field 3
         OrderedListBuilder listBuilder = new OrderedListBuilder();
         ArrayBackedValueStorage itemValue = new ArrayBackedValueStorage();
-        listBuilder.reset((AOrderedListType) MetadataRecordTypes.FUNCTION_RECORDTYPE
-                .getFieldTypes()[MetadataRecordTypes.FUNCTION_ARECORD_FUNCTION_PARAM_LIST_FIELD_INDEX]);
+        listBuilder.reset((AOrderedListType) functionEntity.getRecordType().getFieldTypes()[functionEntity
+                .functionParamListIndex()]);
         for (String p : function.getParameterNames()) {
             itemValue.reset();
             aString.setValue(p);
@@ -334,7 +330,7 @@
         }
         fieldValue.reset();
         listBuilder.write(fieldValue.getDataOutput(), true);
-        recordBuilder.addField(MetadataRecordTypes.FUNCTION_ARECORD_FUNCTION_PARAM_LIST_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(functionEntity.functionParamListIndex(), fieldValue);
 
         // write field 4
         // Note: return type's dataverse name is written later in the open part
@@ -342,29 +338,29 @@
         fieldValue.reset();
         aString.setValue(returnType != null ? returnType.getName() : "");
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.FUNCTION_ARECORD_FUNCTION_RETURN_TYPE_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(functionEntity.functionReturnTypeIndex(), fieldValue);
 
         // write field 5
         fieldValue.reset();
         aString.setValue(function.isExternal() ? "" : function.getFunctionBody());
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.FUNCTION_ARECORD_FUNCTION_DEFINITION_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(functionEntity.functionDefinitionIndex(), fieldValue);
 
         // write field 6
         fieldValue.reset();
         aString.setValue(function.getLanguage());
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.FUNCTION_ARECORD_FUNCTION_LANGUAGE_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(functionEntity.functionLanguageIndex(), fieldValue);
 
         // write field 7
         fieldValue.reset();
         aString.setValue(function.getKind());
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.FUNCTION_ARECORD_FUNCTION_KIND_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(functionEntity.functionKindIndex(), fieldValue);
 
         // write field 8
-        dependenciesListBuilder.reset((AOrderedListType) MetadataRecordTypes.FUNCTION_RECORDTYPE
-                .getFieldTypes()[MetadataRecordTypes.FUNCTION_ARECORD_FUNCTION_DEPENDENCIES_FIELD_INDEX]);
+        dependenciesListBuilder.reset((AOrderedListType) functionEntity.getRecordType().getFieldTypes()[functionEntity
+                .functionDependenciesIndex()]);
         List<List<Triple<DataverseName, String, String>>> dependenciesList = function.getDependencies();
         List<String> subNames = new ArrayList<>();
         for (List<Triple<DataverseName, String, String>> dependencies : dependenciesList) {
@@ -390,7 +386,7 @@
         }
         fieldValue.reset();
         dependenciesListBuilder.write(fieldValue.getDataOutput(), true);
-        recordBuilder.addField(MetadataRecordTypes.FUNCTION_ARECORD_FUNCTION_DEPENDENCIES_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(functionEntity.functionDependenciesIndex(), fieldValue);
 
         writeOpenFields(function);
 
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/IndexTupleTranslator.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/IndexTupleTranslator.java
index a50a834..e803843 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/IndexTupleTranslator.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/IndexTupleTranslator.java
@@ -40,8 +40,7 @@
 import org.apache.asterix.common.transactions.TxnId;
 import org.apache.asterix.formats.nontagged.SerializerDeserializerProvider;
 import org.apache.asterix.metadata.MetadataNode;
-import org.apache.asterix.metadata.bootstrap.MetadataPrimaryIndexes;
-import org.apache.asterix.metadata.bootstrap.MetadataRecordTypes;
+import org.apache.asterix.metadata.bootstrap.IndexEntity;
 import org.apache.asterix.metadata.declared.MetadataManagerUtil;
 import org.apache.asterix.metadata.entities.Dataset;
 import org.apache.asterix.metadata.entities.Datatype;
@@ -83,9 +82,7 @@
  */
 public class IndexTupleTranslator extends AbstractTupleTranslator<Index> {
 
-    // Payload field containing serialized Index.
-    private static final int INDEX_PAYLOAD_TUPLE_FIELD_INDEX = 3;
-
+    private final IndexEntity indexEntity;
     // Field name of open field.
     public static final String GRAM_LENGTH_FIELD_NAME = "GramLength";
     public static final String FULL_TEXT_CONFIG_FIELD_NAME = "FullTextConfig";
@@ -124,10 +121,11 @@
     protected ISerializerDeserializer<AInt8> int8Serde;
 
     @SuppressWarnings("unchecked")
-    protected IndexTupleTranslator(TxnId txnId, MetadataNode metadataNode, boolean getTuple) {
-        super(getTuple, MetadataPrimaryIndexes.INDEX_DATASET, INDEX_PAYLOAD_TUPLE_FIELD_INDEX);
+    protected IndexTupleTranslator(TxnId txnId, MetadataNode metadataNode, boolean getTuple, IndexEntity indexEntity) {
+        super(getTuple, indexEntity.getIndex(), indexEntity.payloadPosition());
         this.txnId = txnId;
         this.metadataNode = metadataNode;
+        this.indexEntity = indexEntity;
         if (getTuple) {
             listBuilder = new OrderedListBuilder();
             innerListBuilder = new OrderedListBuilder();
@@ -150,21 +148,13 @@
     @Override
     protected Index createMetadataEntityFromARecord(ARecord indexRecord) throws AlgebricksException {
         String dataverseCanonicalName =
-                ((AString) indexRecord.getValueByPos(MetadataRecordTypes.INDEX_ARECORD_DATAVERSENAME_FIELD_INDEX))
-                        .getStringValue();
+                ((AString) indexRecord.getValueByPos(indexEntity.dataverseNameIndex())).getStringValue();
         DataverseName dataverseName = DataverseName.createFromCanonicalForm(dataverseCanonicalName);
-        String datasetName =
-                ((AString) indexRecord.getValueByPos(MetadataRecordTypes.INDEX_ARECORD_DATASETNAME_FIELD_INDEX))
-                        .getStringValue();
-        String indexName =
-                ((AString) indexRecord.getValueByPos(MetadataRecordTypes.INDEX_ARECORD_INDEXNAME_FIELD_INDEX))
-                        .getStringValue();
-        IndexType indexType = IndexType.valueOf(
-                ((AString) indexRecord.getValueByPos(MetadataRecordTypes.INDEX_ARECORD_INDEXSTRUCTURE_FIELD_INDEX))
-                        .getStringValue());
-        boolean isPrimaryIndex =
-                ((ABoolean) indexRecord.getValueByPos(MetadataRecordTypes.INDEX_ARECORD_ISPRIMARY_FIELD_INDEX))
-                        .getBoolean();
+        String datasetName = ((AString) indexRecord.getValueByPos(indexEntity.datasetNameIndex())).getStringValue();
+        String indexName = ((AString) indexRecord.getValueByPos(indexEntity.indexNameIndex())).getStringValue();
+        IndexType indexType = IndexType
+                .valueOf(((AString) indexRecord.getValueByPos(indexEntity.indexStructureIndex())).getStringValue());
+        boolean isPrimaryIndex = ((ABoolean) indexRecord.getValueByPos(indexEntity.isPrimaryIndex())).getBoolean();
 
         // Read key names
         List<Pair<List<List<String>>, List<List<String>>>> searchElements = new ArrayList<>();
@@ -172,8 +162,8 @@
             case VALUE:
             case TEXT:
                 // Read the key names from the SearchKeyName field
-                IACursor fieldNameCursor = ((AOrderedList) indexRecord
-                        .getValueByPos(MetadataRecordTypes.INDEX_ARECORD_SEARCHKEY_FIELD_INDEX)).getCursor();
+                IACursor fieldNameCursor =
+                        ((AOrderedList) indexRecord.getValueByPos(indexEntity.searchKeyIndex())).getCursor();
                 AOrderedList fieldNameList;
                 while (fieldNameCursor.next()) {
                     fieldNameList = (AOrderedList) fieldNameCursor.get();
@@ -532,8 +522,7 @@
         if (isEnforcedFieldPos > 0) {
             isEnforcingKeys = ((ABoolean) indexRecord.getValueByPos(isEnforcedFieldPos)).getBoolean();
         }
-        int pendingOp = ((AInt32) indexRecord.getValueByPos(MetadataRecordTypes.INDEX_ARECORD_PENDINGOP_FIELD_INDEX))
-                .getIntegerValue();
+        int pendingOp = ((AInt32) indexRecord.getValueByPos(indexEntity.pendingOpIndex())).getIntegerValue();
 
         return new Index(dataverseName, datasetName, indexName, indexType, indexDetails, isEnforcingKeys,
                 isPrimaryIndex, pendingOp);
@@ -556,36 +545,36 @@
         tupleBuilder.addFieldEndOffset();
 
         // write the payload in the fourth field of the tuple
-        recordBuilder.reset(MetadataRecordTypes.INDEX_RECORDTYPE);
+        recordBuilder.reset(indexEntity.getRecordType());
 
         // write field 0
         fieldValue.reset();
         aString.setValue(dataverseCanonicalName);
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.INDEX_ARECORD_DATAVERSENAME_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(indexEntity.dataverseNameIndex(), fieldValue);
 
         // write field 1
         fieldValue.reset();
         aString.setValue(index.getDatasetName());
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.INDEX_ARECORD_DATASETNAME_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(indexEntity.datasetNameIndex(), fieldValue);
 
         // write field 2
         fieldValue.reset();
         aString.setValue(index.getIndexName());
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.INDEX_ARECORD_INDEXNAME_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(indexEntity.indexNameIndex(), fieldValue);
 
         // write field 3
         IndexType indexType = index.getIndexType();
         fieldValue.reset();
         aString.setValue(indexType.toString());
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.INDEX_ARECORD_INDEXSTRUCTURE_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(indexEntity.indexStructureIndex(), fieldValue);
 
         // write field 4
-        primaryKeyListBuilder.reset((AOrderedListType) MetadataRecordTypes.INDEX_RECORDTYPE
-                .getFieldTypes()[MetadataRecordTypes.INDEX_ARECORD_SEARCHKEY_FIELD_INDEX]);
+        primaryKeyListBuilder
+                .reset((AOrderedListType) indexEntity.getRecordType().getFieldTypes()[indexEntity.searchKeyIndex()]);
         List<List<String>> searchKey;
         switch (Index.IndexCategory.of(indexType)) {
             case VALUE:
@@ -618,7 +607,7 @@
         }
         fieldValue.reset();
         primaryKeyListBuilder.write(fieldValue.getDataOutput(), true);
-        recordBuilder.addField(MetadataRecordTypes.INDEX_ARECORD_SEARCHKEY_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(indexEntity.searchKeyIndex(), fieldValue);
 
         // write field 5
         fieldValue.reset();
@@ -627,18 +616,18 @@
         } else {
             booleanSerde.serialize(ABoolean.FALSE, fieldValue.getDataOutput());
         }
-        recordBuilder.addField(MetadataRecordTypes.INDEX_ARECORD_ISPRIMARY_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(indexEntity.isPrimaryIndex(), fieldValue);
 
         // write field 6
         fieldValue.reset();
         aString.setValue(Calendar.getInstance().getTime().toString());
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.INDEX_ARECORD_TIMESTAMP_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(indexEntity.timestampIndex(), fieldValue);
 
         // write field 7
         fieldValue.reset();
         int32Serde.serialize(new AInt32(index.getPendingOp()), fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.INDEX_ARECORD_PENDINGOP_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(indexEntity.pendingOpIndex(), fieldValue);
 
         // write open fields
         writeOpenFields(index);
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/LibraryTupleTranslator.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/LibraryTupleTranslator.java
index e3e879b..04b1952 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/LibraryTupleTranslator.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/LibraryTupleTranslator.java
@@ -27,8 +27,7 @@
 
 import org.apache.asterix.common.functions.ExternalFunctionLanguage;
 import org.apache.asterix.common.metadata.DataverseName;
-import org.apache.asterix.metadata.bootstrap.MetadataPrimaryIndexes;
-import org.apache.asterix.metadata.bootstrap.MetadataRecordTypes;
+import org.apache.asterix.metadata.bootstrap.LibraryEntity;
 import org.apache.asterix.metadata.entities.Library;
 import org.apache.asterix.metadata.utils.MetadataUtil;
 import org.apache.asterix.om.base.AInt32;
@@ -44,22 +43,19 @@
  */
 public class LibraryTupleTranslator extends AbstractTupleTranslator<Library> {
 
-    // Payload field containing serialized Library.
-    private static final int LIBRARY_PAYLOAD_TUPLE_FIELD_INDEX = 2;
+    private final LibraryEntity libraryEntity;
 
-    protected LibraryTupleTranslator(boolean getTuple) {
-        super(getTuple, MetadataPrimaryIndexes.LIBRARY_DATASET, LIBRARY_PAYLOAD_TUPLE_FIELD_INDEX);
+    protected LibraryTupleTranslator(boolean getTuple, LibraryEntity libraryEntity) {
+        super(getTuple, libraryEntity.getIndex(), libraryEntity.payloadPosition());
+        this.libraryEntity = libraryEntity;
     }
 
     @Override
     protected Library createMetadataEntityFromARecord(ARecord libraryRecord) throws AlgebricksException {
         String dataverseCanonicalName =
-                ((AString) libraryRecord.getValueByPos(MetadataRecordTypes.LIBRARY_ARECORD_DATAVERSENAME_FIELD_INDEX))
-                        .getStringValue();
+                ((AString) libraryRecord.getValueByPos(libraryEntity.dataverseNameIndex())).getStringValue();
         DataverseName dataverseName = DataverseName.createFromCanonicalForm(dataverseCanonicalName);
-        String libraryName =
-                ((AString) libraryRecord.getValueByPos(MetadataRecordTypes.LIBRARY_ARECORD_NAME_FIELD_INDEX))
-                        .getStringValue();
+        String libraryName = ((AString) libraryRecord.getValueByPos(libraryEntity.libraryNameIndex())).getStringValue();
 
         ARecordType libraryRecordType = libraryRecord.getType();
         int pendingOpIdx = libraryRecordType.getFieldIndex(FIELD_NAME_PENDING_OP);
@@ -91,25 +87,25 @@
 
         // write the pay-load in the third field of the tuple
 
-        recordBuilder.reset(MetadataRecordTypes.LIBRARY_RECORDTYPE);
+        recordBuilder.reset(libraryEntity.getRecordType());
 
         // write field 0
         fieldValue.reset();
         aString.setValue(dataverseCanonicalName);
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.LIBRARY_ARECORD_DATAVERSENAME_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(libraryEntity.dataverseNameIndex(), fieldValue);
 
         // write field 1
         fieldValue.reset();
         aString.setValue(library.getName());
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.LIBRARY_ARECORD_NAME_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(libraryEntity.libraryNameIndex(), fieldValue);
 
         // write field 2
         fieldValue.reset();
         aString.setValue(Calendar.getInstance().getTime().toString());
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.LIBRARY_ARECORD_TIMESTAMP_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(libraryEntity.timestampIndex(), fieldValue);
 
         writeOpenFields(library);
 
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/MetadataTupleTranslatorProvider.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/MetadataTupleTranslatorProvider.java
index c2a9ee3..3560e9f 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/MetadataTupleTranslatorProvider.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/MetadataTupleTranslatorProvider.java
@@ -20,76 +20,83 @@
 
 import org.apache.asterix.common.transactions.TxnId;
 import org.apache.asterix.metadata.MetadataNode;
+import org.apache.asterix.metadata.bootstrap.MetadataIndexesProvider;
 
 public class MetadataTupleTranslatorProvider {
 
+    protected final MetadataIndexesProvider mdIndexesProvider;
+
+    public MetadataTupleTranslatorProvider(MetadataIndexesProvider metadataIndexesProvider) {
+        this.mdIndexesProvider = metadataIndexesProvider;
+    }
+
     public CompactionPolicyTupleTranslator getCompactionPolicyTupleTranslator(boolean getTuple) {
-        return new CompactionPolicyTupleTranslator(getTuple);
+        return new CompactionPolicyTupleTranslator(getTuple, mdIndexesProvider.getCompactionPolicyEntity());
     }
 
     public DatasetTupleTranslator getDatasetTupleTranslator(boolean getTuple) {
-        return new DatasetTupleTranslator(getTuple);
+        return new DatasetTupleTranslator(getTuple, mdIndexesProvider.getDatasetEntity());
     }
 
     public DatasourceAdapterTupleTranslator getAdapterTupleTranslator(boolean getTuple) {
-        return new DatasourceAdapterTupleTranslator(getTuple);
+        return new DatasourceAdapterTupleTranslator(getTuple, mdIndexesProvider.getDatasourceAdapterEntity());
     }
 
     public DatatypeTupleTranslator getDataTypeTupleTranslator(TxnId txnId, MetadataNode metadataNode,
             boolean getTuple) {
-        return new DatatypeTupleTranslator(txnId, metadataNode, getTuple);
+        return new DatatypeTupleTranslator(txnId, metadataNode, getTuple, mdIndexesProvider.getDatatypeEntity());
     }
 
     public DataverseTupleTranslator getDataverseTupleTranslator(boolean getTuple) {
-        return new DataverseTupleTranslator(getTuple);
+        return new DataverseTupleTranslator(getTuple, mdIndexesProvider.getDataverseEntity());
     }
 
     public ExternalFileTupleTranslator getExternalFileTupleTranslator(boolean getTuple) {
-        return new ExternalFileTupleTranslator(getTuple);
+        return new ExternalFileTupleTranslator(getTuple, mdIndexesProvider.getExternalFileEntity());
     }
 
     public FeedPolicyTupleTranslator getFeedPolicyTupleTranslator(boolean getTuple) {
-        return new FeedPolicyTupleTranslator(getTuple);
+        return new FeedPolicyTupleTranslator(getTuple, mdIndexesProvider.getFeedPolicyEntity());
     }
 
     public FeedTupleTranslator getFeedTupleTranslator(boolean getTuple) {
-        return new FeedTupleTranslator(getTuple);
+        return new FeedTupleTranslator(getTuple, mdIndexesProvider.getFeedEntity());
     }
 
     public FeedConnectionTupleTranslator getFeedConnectionTupleTranslator(boolean getTuple) {
-        return new FeedConnectionTupleTranslator(getTuple);
+        return new FeedConnectionTupleTranslator(getTuple, mdIndexesProvider.getFeedConnectionEntity());
     }
 
     public FunctionTupleTranslator getFunctionTupleTranslator(TxnId txnId, MetadataNode metadataNode,
             boolean getTuple) {
-        return new FunctionTupleTranslator(txnId, metadataNode, getTuple);
+        return new FunctionTupleTranslator(txnId, metadataNode, getTuple, mdIndexesProvider.getFunctionEntity());
     }
 
     public FullTextConfigMetadataEntityTupleTranslator getFullTextConfigTupleTranslator(boolean getTuple) {
-        return new FullTextConfigMetadataEntityTupleTranslator(getTuple);
+        return new FullTextConfigMetadataEntityTupleTranslator(getTuple, mdIndexesProvider.getFullTextConfigEntity());
     }
 
     public FullTextFilterMetadataEntityTupleTranslator getFullTextFilterTupleTranslator(boolean getTuple) {
-        return new FullTextFilterMetadataEntityTupleTranslator(getTuple);
+        return new FullTextFilterMetadataEntityTupleTranslator(getTuple, mdIndexesProvider.getFullTextFilterEntity());
     }
 
     public IndexTupleTranslator getIndexTupleTranslator(TxnId txnId, MetadataNode metadataNode, boolean getTuple) {
-        return new IndexTupleTranslator(txnId, metadataNode, getTuple);
+        return new IndexTupleTranslator(txnId, metadataNode, getTuple, mdIndexesProvider.getIndexEntity());
     }
 
     public LibraryTupleTranslator getLibraryTupleTranslator(boolean getTuple) {
-        return new LibraryTupleTranslator(getTuple);
+        return new LibraryTupleTranslator(getTuple, mdIndexesProvider.getLibraryEntity());
     }
 
     public NodeTupleTranslator getNodeTupleTranslator(boolean getTuple) {
-        return new NodeTupleTranslator(getTuple);
+        return new NodeTupleTranslator(getTuple, mdIndexesProvider.getNodeEntity());
     }
 
     public NodeGroupTupleTranslator getNodeGroupTupleTranslator(boolean getTuple) {
-        return new NodeGroupTupleTranslator(getTuple);
+        return new NodeGroupTupleTranslator(getTuple, mdIndexesProvider.getNodeGroupEntity());
     }
 
     public SynonymTupleTranslator getSynonymTupleTranslator(boolean getTuple) {
-        return new SynonymTupleTranslator(getTuple);
+        return new SynonymTupleTranslator(getTuple, mdIndexesProvider.getSynonymEntity());
     }
 }
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/NodeGroupTupleTranslator.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/NodeGroupTupleTranslator.java
index 4d6b1b2..db714cf 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/NodeGroupTupleTranslator.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/NodeGroupTupleTranslator.java
@@ -24,8 +24,7 @@
 import java.util.List;
 
 import org.apache.asterix.builders.UnorderedListBuilder;
-import org.apache.asterix.metadata.bootstrap.MetadataPrimaryIndexes;
-import org.apache.asterix.metadata.bootstrap.MetadataRecordTypes;
+import org.apache.asterix.metadata.bootstrap.NodeGroupEntity;
 import org.apache.asterix.metadata.entities.NodeGroup;
 import org.apache.asterix.om.base.ARecord;
 import org.apache.asterix.om.base.AString;
@@ -41,14 +40,13 @@
  */
 public class NodeGroupTupleTranslator extends AbstractTupleTranslator<NodeGroup> {
 
-    // Payload field containing serialized NodeGroup.
-    private static final int NODEGROUP_PAYLOAD_TUPLE_FIELD_INDEX = 1;
-
+    private final NodeGroupEntity nodeGroupEntity;
     protected UnorderedListBuilder listBuilder;
     protected ArrayBackedValueStorage itemValue;
 
-    protected NodeGroupTupleTranslator(boolean getTuple) {
-        super(getTuple, MetadataPrimaryIndexes.NODEGROUP_DATASET, NODEGROUP_PAYLOAD_TUPLE_FIELD_INDEX);
+    protected NodeGroupTupleTranslator(boolean getTuple, NodeGroupEntity nodeGroupEntity) {
+        super(getTuple, nodeGroupEntity.getIndex(), nodeGroupEntity.payloadPosition());
+        this.nodeGroupEntity = nodeGroupEntity;
         if (getTuple) {
             listBuilder = new UnorderedListBuilder();
             itemValue = new ArrayBackedValueStorage();
@@ -57,11 +55,9 @@
 
     @Override
     protected NodeGroup createMetadataEntityFromARecord(ARecord nodeGroupRecord) {
-        String gpName =
-                ((AString) nodeGroupRecord.getValueByPos(MetadataRecordTypes.NODEGROUP_ARECORD_GROUPNAME_FIELD_INDEX))
-                        .getStringValue();
-        IACursor cursor = ((AUnorderedList) nodeGroupRecord
-                .getValueByPos(MetadataRecordTypes.NODEGROUP_ARECORD_NODENAMES_FIELD_INDEX)).getCursor();
+        String gpName = ((AString) nodeGroupRecord.getValueByPos(nodeGroupEntity.groupNameIndex())).getStringValue();
+        IACursor cursor =
+                ((AUnorderedList) nodeGroupRecord.getValueByPos(nodeGroupEntity.nodeNamesIndex())).getCursor();
         List<String> nodeNames = new ArrayList<>();
         while (cursor.next()) {
             nodeNames.add(((AString) cursor.get()).getStringValue());
@@ -78,16 +74,16 @@
         tupleBuilder.addFieldEndOffset();
 
         // write the payload in the second field of the tuple
-        recordBuilder.reset(MetadataRecordTypes.NODEGROUP_RECORDTYPE);
+        recordBuilder.reset(nodeGroupEntity.getRecordType());
         // write field 0
         fieldValue.reset();
         aString.setValue(instance.getNodeGroupName());
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.NODEGROUP_ARECORD_GROUPNAME_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(nodeGroupEntity.groupNameIndex(), fieldValue);
 
         // write field 1
-        listBuilder.reset((AUnorderedListType) MetadataRecordTypes.NODEGROUP_RECORDTYPE
-                .getFieldTypes()[MetadataRecordTypes.NODEGROUP_ARECORD_NODENAMES_FIELD_INDEX]);
+        listBuilder.reset(
+                (AUnorderedListType) nodeGroupEntity.getRecordType().getFieldTypes()[nodeGroupEntity.nodeNamesIndex()]);
         List<String> nodeNames = instance.getNodeNames();
         for (String nodeName : nodeNames) {
             itemValue.reset();
@@ -97,13 +93,13 @@
         }
         fieldValue.reset();
         listBuilder.write(fieldValue.getDataOutput(), true);
-        recordBuilder.addField(MetadataRecordTypes.NODEGROUP_ARECORD_NODENAMES_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(nodeGroupEntity.nodeNamesIndex(), fieldValue);
 
         // write field 2
         fieldValue.reset();
         aString.setValue(Calendar.getInstance().getTime().toString());
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.NODEGROUP_ARECORD_TIMESTAMP_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(nodeGroupEntity.timestampIndex(), fieldValue);
 
         recordBuilder.write(tupleBuilder.getDataOutput(), true);
         tupleBuilder.addFieldEndOffset();
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/NodeTupleTranslator.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/NodeTupleTranslator.java
index f0fbc4d..c519868 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/NodeTupleTranslator.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/NodeTupleTranslator.java
@@ -19,8 +19,7 @@
 
 package org.apache.asterix.metadata.entitytupletranslators;
 
-import org.apache.asterix.metadata.bootstrap.MetadataPrimaryIndexes;
-import org.apache.asterix.metadata.bootstrap.MetadataRecordTypes;
+import org.apache.asterix.metadata.bootstrap.NodeEntity;
 import org.apache.asterix.metadata.entities.Node;
 import org.apache.asterix.om.base.AMutableInt64;
 import org.apache.asterix.om.base.ARecord;
@@ -33,13 +32,12 @@
  */
 public class NodeTupleTranslator extends AbstractTupleTranslator<Node> {
 
-    // Payload field containing serialized Node.
-    private static final int NODE_PAYLOAD_TUPLE_FIELD_INDEX = 1;
-
+    private final NodeEntity nodeEntity;
     protected AMutableInt64 aInt64;
 
-    protected NodeTupleTranslator(boolean getTuple) {
-        super(getTuple, MetadataPrimaryIndexes.NODE_DATASET, NODE_PAYLOAD_TUPLE_FIELD_INDEX);
+    protected NodeTupleTranslator(boolean getTuple, NodeEntity nodeEntity) {
+        super(getTuple, nodeEntity.getIndex(), nodeEntity.payloadPosition());
+        this.nodeEntity = nodeEntity;
         if (getTuple) {
             aInt64 = new AMutableInt64(-1);
         }
@@ -80,24 +78,24 @@
         tupleBuilder.addFieldEndOffset();
 
         // write the payload in the second field of the tuple
-        recordBuilder.reset(MetadataRecordTypes.NODE_RECORDTYPE);
+        recordBuilder.reset(nodeEntity.getRecordType());
         // write field 0
         fieldValue.reset();
         aString.setValue(instance.getNodeName());
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.NODE_ARECORD_NODENAME_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(nodeEntity.nodeNameIndex(), fieldValue);
 
         // write field 1
         fieldValue.reset();
         aInt64.setValue(instance.getNumberOfCores());
         int64Serde.serialize(aInt64, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.NODE_ARECORD_NUMBEROFCORES_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(nodeEntity.numberOfCoresIndex(), fieldValue);
 
         // write field 2
         fieldValue.reset();
         aInt64.setValue(instance.getWorkingMemorySize());
         int64Serde.serialize(aInt64, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.NODE_ARECORD_WORKINGMEMORYSIZE_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(nodeEntity.memorySizeIndex(), fieldValue);
 
         // write field 3
         // listBuilder.reset((AOrderedListType)
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/SynonymTupleTranslator.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/SynonymTupleTranslator.java
index 6bad2d4..e3f2bdb 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/SynonymTupleTranslator.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/SynonymTupleTranslator.java
@@ -20,8 +20,7 @@
 package org.apache.asterix.metadata.entitytupletranslators;
 
 import org.apache.asterix.common.metadata.DataverseName;
-import org.apache.asterix.metadata.bootstrap.MetadataPrimaryIndexes;
-import org.apache.asterix.metadata.bootstrap.MetadataRecordTypes;
+import org.apache.asterix.metadata.bootstrap.SynonymEntity;
 import org.apache.asterix.metadata.entities.Synonym;
 import org.apache.asterix.om.base.ARecord;
 import org.apache.asterix.om.base.AString;
@@ -34,32 +33,26 @@
  */
 public final class SynonymTupleTranslator extends AbstractTupleTranslator<Synonym> {
 
-    // Payload field containing serialized Synonym.
+    private final SynonymEntity synonymEntity;
 
-    private static final int SYNONYM_PAYLOAD_TUPLE_FIELD_INDEX = 2;
-
-    protected SynonymTupleTranslator(boolean getTuple) {
-        super(getTuple, MetadataPrimaryIndexes.SYNONYM_DATASET, SYNONYM_PAYLOAD_TUPLE_FIELD_INDEX);
+    protected SynonymTupleTranslator(boolean getTuple, SynonymEntity synonymEntity) {
+        super(getTuple, synonymEntity.getIndex(), synonymEntity.payloadPosition());
+        this.synonymEntity = synonymEntity;
     }
 
     @Override
     protected Synonym createMetadataEntityFromARecord(ARecord synonymRecord) throws AlgebricksException {
         String dataverseCanonicalName =
-                ((AString) synonymRecord.getValueByPos(MetadataRecordTypes.SYNONYM_ARECORD_DATAVERSENAME_FIELD_INDEX))
-                        .getStringValue();
+                ((AString) synonymRecord.getValueByPos(synonymEntity.dataverseNameIndex())).getStringValue();
         DataverseName dataverseName = DataverseName.createFromCanonicalForm(dataverseCanonicalName);
 
-        String synonymName =
-                ((AString) synonymRecord.getValueByPos(MetadataRecordTypes.SYNONYM_ARECORD_SYNONYMNAME_FIELD_INDEX))
-                        .getStringValue();
+        String synonymName = ((AString) synonymRecord.getValueByPos(synonymEntity.synonymNameIndex())).getStringValue();
 
-        String objectDataverseCanonicalName = ((AString) synonymRecord
-                .getValueByPos(MetadataRecordTypes.SYNONYM_ARECORD_OBJECTDATAVERSENAME_FIELD_INDEX)).getStringValue();
+        String objectDataverseCanonicalName =
+                ((AString) synonymRecord.getValueByPos(synonymEntity.objectDataverseNameIndex())).getStringValue();
         DataverseName objectDataverseName = DataverseName.createFromCanonicalForm(objectDataverseCanonicalName);
 
-        String objectName =
-                ((AString) synonymRecord.getValueByPos(MetadataRecordTypes.SYNONYM_ARECORD_OBJECTNAME_FIELD_INDEX))
-                        .getStringValue();
+        String objectName = ((AString) synonymRecord.getValueByPos(synonymEntity.objectNameIndex())).getStringValue();
 
         return new Synonym(dataverseName, synonymName, objectDataverseName, objectName);
     }
@@ -80,31 +73,31 @@
 
         // write the pay-load in the third field of the tuple
 
-        recordBuilder.reset(MetadataRecordTypes.SYNONYM_RECORDTYPE);
+        recordBuilder.reset(synonymEntity.getRecordType());
 
         // write field 0
         fieldValue.reset();
         aString.setValue(dataverseCanonicalName);
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.SYNONYM_ARECORD_DATAVERSENAME_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(synonymEntity.dataverseNameIndex(), fieldValue);
 
         // write field 1
         fieldValue.reset();
         aString.setValue(synonym.getSynonymName());
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.SYNONYM_ARECORD_SYNONYMNAME_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(synonymEntity.synonymNameIndex(), fieldValue);
 
         // write field 2
         fieldValue.reset();
         aString.setValue(synonym.getObjectDataverseName().getCanonicalForm());
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.SYNONYM_ARECORD_OBJECTDATAVERSENAME_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(synonymEntity.objectDataverseNameIndex(), fieldValue);
 
         // write field 3
         fieldValue.reset();
         aString.setValue(synonym.getObjectName());
         stringSerde.serialize(aString, fieldValue.getDataOutput());
-        recordBuilder.addField(MetadataRecordTypes.SYNONYM_ARECORD_OBJECTNAME_FIELD_INDEX, fieldValue);
+        recordBuilder.addField(synonymEntity.objectNameIndex(), fieldValue);
 
         // write record
         recordBuilder.write(tupleBuilder.getDataOutput(), true);
diff --git a/asterixdb/asterix-metadata/src/test/java/org/apache/asterix/metadata/entitytupletranslators/DatasetTupleTranslatorTest.java b/asterixdb/asterix-metadata/src/test/java/org/apache/asterix/metadata/entitytupletranslators/DatasetTupleTranslatorTest.java
index b6f9df7..8e40d3e 100644
--- a/asterixdb/asterix-metadata/src/test/java/org/apache/asterix/metadata/entitytupletranslators/DatasetTupleTranslatorTest.java
+++ b/asterixdb/asterix-metadata/src/test/java/org/apache/asterix/metadata/entitytupletranslators/DatasetTupleTranslatorTest.java
@@ -25,6 +25,7 @@
 
 import org.apache.asterix.common.config.DatasetConfig.DatasetType;
 import org.apache.asterix.common.metadata.DataverseName;
+import org.apache.asterix.metadata.bootstrap.DatasetEntity;
 import org.apache.asterix.metadata.dataset.DatasetFormatInfo;
 import org.apache.asterix.metadata.entities.Dataset;
 import org.apache.asterix.metadata.entities.InternalDatasetDetails;
@@ -58,7 +59,7 @@
                     "MetaType", "DEFAULT_NG_ALL_NODES", "prefix", compactionPolicyProperties, details,
                     Collections.emptyMap(), DatasetType.INTERNAL, 115, 0, CompressionManager.NONE,
                     DatasetFormatInfo.SYSTEM_DEFAULT);
-            DatasetTupleTranslator dtTranslator = new DatasetTupleTranslator(true);
+            DatasetTupleTranslator dtTranslator = new DatasetTupleTranslator(true, DatasetEntity.of(false));
             ITupleReference tuple = dtTranslator.getTupleFromMetadataEntity(dataset);
             Dataset deserializedDataset = dtTranslator.getMetadataEntityFromTuple(tuple);
             Assert.assertEquals(dataset.getMetaItemTypeDataverseName(),
diff --git a/asterixdb/asterix-metadata/src/test/java/org/apache/asterix/metadata/entitytupletranslators/IndexTupleTranslatorTest.java b/asterixdb/asterix-metadata/src/test/java/org/apache/asterix/metadata/entitytupletranslators/IndexTupleTranslatorTest.java
index 9f54478..07a7e33 100644
--- a/asterixdb/asterix-metadata/src/test/java/org/apache/asterix/metadata/entitytupletranslators/IndexTupleTranslatorTest.java
+++ b/asterixdb/asterix-metadata/src/test/java/org/apache/asterix/metadata/entitytupletranslators/IndexTupleTranslatorTest.java
@@ -32,6 +32,7 @@
 import org.apache.asterix.common.config.DatasetConfig.IndexType;
 import org.apache.asterix.common.metadata.DataverseName;
 import org.apache.asterix.metadata.MetadataNode;
+import org.apache.asterix.metadata.bootstrap.IndexEntity;
 import org.apache.asterix.metadata.dataset.DatasetFormatInfo;
 import org.apache.asterix.metadata.entities.Dataset;
 import org.apache.asterix.metadata.entities.Datatype;
@@ -83,7 +84,8 @@
                     new ARecordType("", new String[] { "row_id" }, new IAType[] { BuiltinType.AINT64 }, true), true));
             when(mockMetadataNode.getDataset(any(), any(DataverseName.class), anyString())).thenReturn(dataset);
 
-            IndexTupleTranslator idxTranslator = new IndexTupleTranslator(null, mockMetadataNode, true);
+            IndexTupleTranslator idxTranslator =
+                    new IndexTupleTranslator(null, mockMetadataNode, true, IndexEntity.of(false));
             ITupleReference tuple = idxTranslator.getTupleFromMetadataEntity(index);
             Index deserializedIndex = idxTranslator.getMetadataEntityFromTuple(tuple);
             if (indicator == null) {