accumulo-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ctubb...@apache.org
Subject [accumulo] branch main updated: Clean up KeyExtent (#1702)
Date Wed, 09 Sep 2020 00:55:37 GMT
This is an automated email from the ASF dual-hosted git repository.

ctubbsii pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/accumulo.git


The following commit(s) were added to refs/heads/main by this push:
     new 4051a8c  Clean up KeyExtent (#1702)
4051a8c is described below

commit 4051a8c23be6f901585e07a6170b57383b2ecd69
Author: Christopher Tubbs <ctubbsii@apache.org>
AuthorDate: Tue Sep 8 20:55:23 2020 -0400

    Clean up KeyExtent (#1702)
    
    * Replace confusing overloaded constructors with self-descriptive
      static factory methods
    * Move metadata serialization into Metadata schema class
    * Remove unnecessary WritableComparable interface
    * Improve javadocs
    * Replace private equals method with Objects.equals
    * Remove methods only used in tests
    * Use TableId instead of String and fix variable name (tableId
      instead of incorrect tablename)
    * Shorten accessor method names
    * Make KeyExtent closer to immutable (it's not truly immutable,
      because Text objects that represent endRow and prevEndRow are
      mutable)
---
 .../core/clientImpl/ActiveCompactionImpl.java      |   4 +-
 .../accumulo/core/clientImpl/ActiveScanImpl.java   |   2 +-
 .../accumulo/core/clientImpl/OfflineIterator.java  |  10 +-
 .../core/clientImpl/TableOperationsImpl.java       |  16 +-
 .../core/clientImpl/TabletLocatorImpl.java         |  37 +-
 .../TabletServerBatchReaderIterator.java           |   6 +-
 .../core/clientImpl/TabletServerBatchWriter.java   |  14 +-
 .../accumulo/core/clientImpl/ThriftScanner.java    |  12 +-
 .../accumulo/core/clientImpl/Translator.java       |   2 +-
 .../apache/accumulo/core/clientImpl/bulk/Bulk.java |   2 +-
 .../accumulo/core/clientImpl/bulk/BulkImport.java  |   6 +-
 .../clientImpl/bulk/ConcurrentKeyExtentCache.java  |   8 +-
 .../mapreduce/lib/InputConfigurator.java           |  10 +-
 .../java/org/apache/accumulo/core/data/Range.java  |   2 +-
 .../apache/accumulo/core/dataImpl/KeyExtent.java   | 651 +++++++--------------
 .../accumulo/core/dataImpl/TabletIdImpl.java       |   6 +-
 .../core/iteratorsImpl/system/MultiIterator.java   |   2 +-
 .../core/metadata/MetadataLocationObtainer.java    |  22 +-
 .../apache/accumulo/core/metadata/RootTable.java   |   2 +-
 .../core/metadata/TableMetadataServicer.java       |  16 +-
 .../core/metadata/schema/LinkingIterator.java      |   8 +-
 .../core/metadata/schema/MetadataSchema.java       |  74 ++-
 .../core/metadata/schema/RootTabletMetadata.java   |   7 +-
 .../core/metadata/schema/TabletMetadata.java       |  10 +-
 .../core/metadata/schema/TabletsMetadata.java      |   6 +-
 .../org/apache/accumulo/core/summary/Gatherer.java |   4 +-
 .../accumulo/core/tabletserver/log/LogEntry.java   |  13 +-
 .../java/org/apache/accumulo/core/util/Merge.java  |   6 +-
 .../core/clientImpl/TabletLocatorImplTest.java     |  27 +-
 .../apache/accumulo/core/data/KeyExtentTest.java   | 134 +----
 .../org/apache/accumulo/core/data/RangeTest.java   |  24 +-
 .../apache/accumulo/core/file/rfile/RFileTest.java |   9 +-
 .../core/metadata/schema/LinkingIteratorTest.java  |  11 +-
 .../core/metadata/schema/MetadataSchemaTest.java   |  41 ++
 .../core/metadata/schema/TabletMetadataTest.java   |  13 +-
 .../core/tabletserver}/log/LogEntryTest.java       |  49 +-
 .../org/apache/accumulo/core/util/MergeTest.java   |   8 +-
 .../mapreduce/lib/InputConfigurator.java           |  10 +-
 .../accumulo/server/client/BulkImporter.java       |   6 +-
 .../server/constraints/MetadataConstraints.java    |   6 +-
 .../apache/accumulo/server/init/Initialize.java    |   5 +-
 .../master/balancer/ChaoticLoadBalancer.java       |   2 +-
 .../master/balancer/DefaultLoadBalancer.java       |   2 +-
 .../server/master/balancer/GroupBalancer.java      |   2 +-
 .../balancer/HostRegexTableLoadBalancer.java       |   8 +-
 .../server/master/balancer/RegexGroupBalancer.java |   2 +-
 .../server/master/balancer/TableLoadBalancer.java  |   2 +-
 .../accumulo/server/master/state/MergeInfo.java    |  10 +-
 .../server/master/state/MetaDataStateStore.java    |   8 +-
 .../server/master/state/MetaDataTableScanner.java  |  10 +-
 .../server/master/state/TabletLocationState.java   |   2 +-
 .../master/state/TabletStateChangeIterator.java    |  12 +-
 .../server/master/state/TabletStateStore.java      |   2 +-
 .../server/metadata/TabletMutatorBase.java         |   4 +-
 .../server/metadata/TabletsMutatorImpl.java        |   2 +-
 .../tabletserver/LargestFirstMemoryManager.java    |   4 +-
 .../server/util/CheckForMetadataProblems.java      |  52 +-
 .../accumulo/server/util/FindOfflineTablets.java   |   4 +-
 .../accumulo/server/util/MasterMetadataUtil.java   |  16 +-
 .../accumulo/server/util/MetadataTableUtil.java    |  31 +-
 .../server/util/RemoveEntriesForMissingFiles.java  |   2 +-
 .../accumulo/server/util/ReplicationTableUtil.java |   2 +-
 .../accumulo/server/util/TableDiskUsage.java       |   2 +-
 .../server/util/VerifyTabletAssignments.java       |  23 +-
 .../accumulo/server/client/BulkImporterTest.java   |   4 +-
 .../BaseHostRegexTableLoadBalancerTest.java        |   2 +-
 .../master/balancer/ChaoticLoadBalancerTest.java   |   4 +-
 .../master/balancer/DefaultLoadBalancerTest.java   |   6 +-
 .../server/master/balancer/GroupBalancerTest.java  |   4 +-
 ...tRegexTableLoadBalancerReconfigurationTest.java |   2 +-
 .../master/balancer/TableLoadBalancerTest.java     |   2 +-
 .../server/master/state/MergeInfoTest.java         |  28 +-
 .../master/state/TabletLocationStateTest.java      |   2 +-
 .../server/util/ReplicationTableUtilTest.java      |   2 +-
 .../gc/GarbageCollectWriteAheadLogsTest.java       |   2 +-
 .../java/org/apache/accumulo/master/Master.java    |   8 +-
 .../master/MasterClientServiceHandler.java         |  19 +-
 .../apache/accumulo/master/TabletGroupWatcher.java |  63 +-
 .../apache/accumulo/master/state/MergeStats.java   |  26 +-
 .../master/tableOps/bulkVer1/CopyFailed.java       |   2 +-
 .../master/tableOps/bulkVer2/LoadFiles.java        |   8 +-
 .../master/tableOps/bulkVer2/PrepBulkImport.java   |  15 +-
 .../master/tableOps/create/PopulateMetadata.java   |   4 +-
 .../accumulo/master/tableOps/delete/CleanUp.java   |   2 +-
 .../tableOps/tableExport/WriteExportFiles.java     |   4 +-
 .../tableImport/PopulateMetadataTable.java         |   4 +-
 .../accumulo/master/upgrade/Upgrader9to10.java     |   4 +-
 .../tableOps/bulkVer2/PrepBulkImportTest.java      |  10 +-
 .../monitor/rest/tables/TablesResource.java        |   4 +-
 .../rest/tservers/TabletServerResource.java        |   8 +-
 .../apache/accumulo/tserver/AssignmentHandler.java |   2 +-
 .../org/apache/accumulo/tserver/FileManager.java   |  10 +-
 .../org/apache/accumulo/tserver/TabletServer.java  |   6 +-
 .../tserver/TabletServerResourceManager.java       |   4 +-
 .../accumulo/tserver/ThriftClientHandler.java      |  53 +-
 .../apache/accumulo/tserver/logger/LogFileKey.java |   5 +-
 .../tserver/replication/AccumuloReplicaSystem.java |   4 +-
 .../accumulo/tserver/session/MultiScanSession.java |   2 +-
 .../accumulo/tserver/session/SessionManager.java   |  10 +-
 .../tserver/session/SingleScanSession.java         |   2 +-
 .../accumulo/tserver/tablet/CompactableImpl.java   |   2 +-
 .../accumulo/tserver/tablet/CompactableUtils.java  |  12 +-
 .../apache/accumulo/tserver/tablet/Compactor.java  |   8 +-
 .../accumulo/tserver/tablet/DatafileManager.java   |   2 +-
 .../accumulo/tserver/tablet/MinorCompactor.java    |  18 +-
 .../accumulo/tserver/tablet/ScanDataSource.java    |   2 +-
 .../org/apache/accumulo/tserver/tablet/Tablet.java |  38 +-
 .../accumulo/tserver/tablet/TabletMemory.java      |   4 +-
 .../accumulo/tserver/CheckTabletMetadataTest.java  |   2 +-
 .../accumulo/shell/commands/GetSplitsCommand.java  |  10 +-
 .../java/org/apache/accumulo/test/CloneIT.java     |  20 +-
 .../test/MasterRepairsDualAssignmentIT.java        |   4 +-
 .../accumulo/test/MetaConstraintRetryIT.java       |   2 +-
 .../test/MissingWalHeaderCompletesRecoveryIT.java  |   4 +-
 .../org/apache/accumulo/test/SplitRecoveryIT.java  |   8 +-
 .../java/org/apache/accumulo/test/VolumeIT.java    |   2 +-
 .../accumulo/test/functional/BulkFailureIT.java    |   6 +-
 .../test/functional/MasterAssignmentIT.java        |   2 +-
 .../apache/accumulo/test/functional/SplitIT.java   |   6 +-
 .../accumulo/test/functional/SplitRecoveryIT.java  |  16 +-
 .../apache/accumulo/test/functional/TableIT.java   |   2 +-
 .../functional/TabletStateChangeIteratorIT.java    |   8 +-
 .../accumulo/test/functional/WALSunnyDayIT.java    |   4 +-
 .../apache/accumulo/test/master/MergeStateIT.java  |  18 +-
 .../accumulo/test/master/SuspendedTabletsIT.java   |   2 +-
 .../accumulo/test/performance/NullTserver.java     |   2 +-
 .../test/performance/scan/CollectTabletStats.java  |  12 +-
 .../accumulo/test/replication/ReplicationIT.java   |  42 +-
 .../UnusedWalDoesntCloseReplicationStatusIT.java   |   2 +-
 129 files changed, 950 insertions(+), 1152 deletions(-)

diff --git a/core/src/main/java/org/apache/accumulo/core/clientImpl/ActiveCompactionImpl.java b/core/src/main/java/org/apache/accumulo/core/clientImpl/ActiveCompactionImpl.java
index 4a7cdc7..380e91b 100644
--- a/core/src/main/java/org/apache/accumulo/core/clientImpl/ActiveCompactionImpl.java
+++ b/core/src/main/java/org/apache/accumulo/core/clientImpl/ActiveCompactionImpl.java
@@ -46,12 +46,12 @@ public class ActiveCompactionImpl extends ActiveCompaction {
 
   @Override
   public String getTable() throws TableNotFoundException {
-    return Tables.getTableName(context, new KeyExtent(tac.getExtent()).getTableId());
+    return Tables.getTableName(context, KeyExtent.fromThrift(tac.getExtent()).tableId());
   }
 
   @Override
   public TabletId getTablet() {
-    return new TabletIdImpl(new KeyExtent(tac.getExtent()));
+    return new TabletIdImpl(KeyExtent.fromThrift(tac.getExtent()));
   }
 
   @Override
diff --git a/core/src/main/java/org/apache/accumulo/core/clientImpl/ActiveScanImpl.java b/core/src/main/java/org/apache/accumulo/core/clientImpl/ActiveScanImpl.java
index 52ff699..642cb00 100644
--- a/core/src/main/java/org/apache/accumulo/core/clientImpl/ActiveScanImpl.java
+++ b/core/src/main/java/org/apache/accumulo/core/clientImpl/ActiveScanImpl.java
@@ -67,7 +67,7 @@ public class ActiveScanImpl extends ActiveScan {
     this.tableName = Tables.getTableName(context, TableId.of(activeScan.tableId));
     this.type = ScanType.valueOf(activeScan.getType().name());
     this.state = ScanState.valueOf(activeScan.state.name());
-    this.extent = new KeyExtent(activeScan.extent);
+    this.extent = KeyExtent.fromThrift(activeScan.extent);
     this.authorizations = new Authorizations(activeScan.authorizations);
 
     this.columns = new ArrayList<>(activeScan.columns.size());
diff --git a/core/src/main/java/org/apache/accumulo/core/clientImpl/OfflineIterator.java b/core/src/main/java/org/apache/accumulo/core/clientImpl/OfflineIterator.java
index 2e54329..95c618c 100644
--- a/core/src/main/java/org/apache/accumulo/core/clientImpl/OfflineIterator.java
+++ b/core/src/main/java/org/apache/accumulo/core/clientImpl/OfflineIterator.java
@@ -222,20 +222,20 @@ class OfflineIterator implements Iterator<Entry<Key,Value>> {
       else
         startRow = new Text();
 
-      nextRange = new Range(TabletsSection.getRow(tableId, startRow), true, null, false);
+      nextRange = new Range(TabletsSection.encodeRow(tableId, startRow), true, null, false);
     } else {
 
-      if (currentExtent.getEndRow() == null) {
+      if (currentExtent.endRow() == null) {
         iter = null;
         return;
       }
 
-      if (range.afterEndKey(new Key(currentExtent.getEndRow()).followingKey(PartialKey.ROW))) {
+      if (range.afterEndKey(new Key(currentExtent.endRow()).followingKey(PartialKey.ROW))) {
         iter = null;
         return;
       }
 
-      nextRange = new Range(currentExtent.getMetadataEntry(), false, null, false);
+      nextRange = new Range(currentExtent.toMetaRow(), false, null, false);
     }
 
     TabletMetadata tablet = getTabletFiles(nextRange);
@@ -254,7 +254,7 @@ class OfflineIterator implements Iterator<Entry<Key,Value>> {
       tablet = getTabletFiles(nextRange);
     }
 
-    if (!tablet.getExtent().getTableId().equals(tableId)) {
+    if (!tablet.getExtent().tableId().equals(tableId)) {
       throw new AccumuloException(
           " did not find tablets for table " + tableId + " " + tablet.getExtent());
     }
diff --git a/core/src/main/java/org/apache/accumulo/core/clientImpl/TableOperationsImpl.java b/core/src/main/java/org/apache/accumulo/core/clientImpl/TableOperationsImpl.java
index 87aa64b..207e245 100644
--- a/core/src/main/java/org/apache/accumulo/core/clientImpl/TableOperationsImpl.java
+++ b/core/src/main/java/org/apache/accumulo/core/clientImpl/TableOperationsImpl.java
@@ -689,8 +689,8 @@ public class TableOperationsImpl extends TableOperationsHelper {
     ArrayList<Text> endRows = new ArrayList<>(tabletLocations.size());
 
     for (KeyExtent ke : tabletLocations.keySet())
-      if (ke.getEndRow() != null)
-        endRows.add(ke.getEndRow());
+      if (ke.endRow() != null)
+        endRows.add(ke.endRow());
 
     return endRows;
 
@@ -1176,8 +1176,8 @@ public class TableOperationsImpl extends TableOperationsHelper {
       if (unmergedExtents.size() >= 2) {
         KeyExtent first = unmergedExtents.removeFirst();
         KeyExtent second = unmergedExtents.removeFirst();
-        first.setEndRow(second.getEndRow());
-        mergedExtents.add(first);
+        KeyExtent merged = new KeyExtent(first.tableId(), second.endRow(), first.prevEndRow());
+        mergedExtents.add(merged);
       } else {
         mergedExtents.addAll(unmergedExtents);
         unmergedExtents.clear();
@@ -1282,7 +1282,7 @@ public class TableOperationsImpl extends TableOperationsHelper {
 
       Range range;
       if (startRow == null || lastRow == null)
-        range = new KeyExtent(tableId, null, null).toMetadataRange();
+        range = new KeyExtent(tableId, null, null).toMetaRange();
       else
         range = new Range(startRow, lastRow);
 
@@ -1306,16 +1306,16 @@ public class TableOperationsImpl extends TableOperationsHelper {
             && (loc == null || loc.getType() == LocationType.FUTURE))
             || (expectedState == TableState.OFFLINE && loc != null)) {
           if (continueRow == null)
-            continueRow = tablet.getExtent().getMetadataEntry();
+            continueRow = tablet.getExtent().toMetaRow();
           waitFor++;
-          lastRow = tablet.getExtent().getMetadataEntry();
+          lastRow = tablet.getExtent().toMetaRow();
 
           if (loc != null) {
             serverCounts.increment(loc.getId(), 1);
           }
         }
 
-        if (!tablet.getExtent().getTableId().equals(tableId)) {
+        if (!tablet.getExtent().tableId().equals(tableId)) {
           throw new AccumuloException(
               "Saw unexpected table Id " + tableId + " " + tablet.getExtent());
         }
diff --git a/core/src/main/java/org/apache/accumulo/core/clientImpl/TabletLocatorImpl.java b/core/src/main/java/org/apache/accumulo/core/clientImpl/TabletLocatorImpl.java
index 6869d6a..5e4d4e4 100644
--- a/core/src/main/java/org/apache/accumulo/core/clientImpl/TabletLocatorImpl.java
+++ b/core/src/main/java/org/apache/accumulo/core/clientImpl/TabletLocatorImpl.java
@@ -293,14 +293,14 @@ public class TabletLocatorImpl extends TabletLocator {
 
       tabletLocations.add(tl);
 
-      while (tl.tablet_extent.getEndRow() != null && !range
-          .afterEndKey(new Key(tl.tablet_extent.getEndRow()).followingKey(PartialKey.ROW))) {
+      while (tl.tablet_extent.endRow() != null
+          && !range.afterEndKey(new Key(tl.tablet_extent.endRow()).followingKey(PartialKey.ROW))) {
         if (useCache) {
-          Text row = new Text(tl.tablet_extent.getEndRow());
+          Text row = new Text(tl.tablet_extent.endRow());
           row.append(new byte[] {0}, 0, 1);
           tl = lcSession.checkLock(locateTabletInCache(row));
         } else {
-          tl = _locateTablet(context, tl.tablet_extent.getEndRow(), true, false, false, lcSession);
+          tl = _locateTablet(context, tl.tablet_extent.endRow(), true, false, false, lcSession);
         }
 
         if (tl == null) {
@@ -490,7 +490,7 @@ public class TabletLocatorImpl extends TabletLocator {
       while (locations != null && locations.getLocations().isEmpty()
           && locations.getLocationless().isEmpty()) {
         // try the next tablet, the current tablet does not have any tablets that overlap the row
-        Text er = ptl.tablet_extent.getEndRow();
+        Text er = ptl.tablet_extent.endRow();
         if (er != null && er.compareTo(lastTabletRow) < 0) {
           // System.out.println("er "+er+" ltr "+lastTabletRow);
           ptl = parent.locateTablet(context, er, true, retry);
@@ -517,17 +517,16 @@ public class TabletLocatorImpl extends TabletLocator {
         TabletLocation locToCache;
 
         // create new location if current prevEndRow == endRow
-        if ((lastEndRow != null) && (ke.getPrevEndRow() != null)
-            && ke.getPrevEndRow().equals(lastEndRow)) {
-          locToCache =
-              new TabletLocation(new KeyExtent(ke.getTableId(), ke.getEndRow(), lastEndRow),
-                  tabletLocation.tablet_location, tabletLocation.tablet_session);
+        if ((lastEndRow != null) && (ke.prevEndRow() != null)
+            && ke.prevEndRow().equals(lastEndRow)) {
+          locToCache = new TabletLocation(new KeyExtent(ke.tableId(), ke.endRow(), lastEndRow),
+              tabletLocation.tablet_location, tabletLocation.tablet_session);
         } else {
           locToCache = tabletLocation;
         }
 
         // save endRow for next iteration
-        lastEndRow = locToCache.tablet_extent.getEndRow();
+        lastEndRow = locToCache.tablet_extent.endRow();
 
         updateCache(locToCache, lcSession);
       }
@@ -536,7 +535,7 @@ public class TabletLocatorImpl extends TabletLocator {
   }
 
   private void updateCache(TabletLocation tabletLocation, LockCheckerSession lcSession) {
-    if (!tabletLocation.tablet_extent.getTableId().equals(tableId)) {
+    if (!tabletLocation.tablet_extent.tableId().equals(tableId)) {
       // sanity check
       throw new IllegalStateException(
           "Unexpected extent returned " + tableId + "  " + tabletLocation.tablet_extent);
@@ -556,7 +555,7 @@ public class TabletLocatorImpl extends TabletLocator {
       return;
 
     // add it to cache
-    Text er = tabletLocation.tablet_extent.getEndRow();
+    Text er = tabletLocation.tablet_extent.endRow();
     if (er == null)
       er = MAX_TEXT;
     metaCache.put(er, tabletLocation);
@@ -568,7 +567,7 @@ public class TabletLocatorImpl extends TabletLocator {
   static void removeOverlapping(TreeMap<Text,TabletLocation> metaCache, KeyExtent nke) {
     Iterator<Entry<Text,TabletLocation>> iter = null;
 
-    if (nke.getPrevEndRow() == null) {
+    if (nke.prevEndRow() == null) {
       iter = metaCache.entrySet().iterator();
     } else {
       Text row = rowAfterPrevRow(nke);
@@ -590,12 +589,12 @@ public class TabletLocatorImpl extends TabletLocator {
   }
 
   private static boolean stopRemoving(KeyExtent nke, KeyExtent ke) {
-    return ke.getPrevEndRow() != null && nke.getEndRow() != null
-        && ke.getPrevEndRow().compareTo(nke.getEndRow()) >= 0;
+    return ke.prevEndRow() != null && nke.endRow() != null
+        && ke.prevEndRow().compareTo(nke.endRow()) >= 0;
   }
 
   private static Text rowAfterPrevRow(KeyExtent nke) {
-    Text row = new Text(nke.getPrevEndRow());
+    Text row = new Text(nke.prevEndRow());
     row.append(new byte[] {0}, 0, 1);
     return row;
   }
@@ -612,7 +611,7 @@ public class TabletLocatorImpl extends TabletLocator {
 
     if (entry != null) {
       KeyExtent ke = entry.getValue().tablet_extent;
-      if (ke.getPrevEndRow() == null || ke.getPrevEndRow().compareTo(row) < 0) {
+      if (ke.prevEndRow() == null || ke.prevEndRow().compareTo(row) < 0) {
         return entry.getValue();
       }
     }
@@ -692,7 +691,7 @@ public class TabletLocatorImpl extends TabletLocator {
       List<Range> lookups = new ArrayList<>(badExtents.size());
 
       for (KeyExtent be : badExtents) {
-        lookups.add(be.toMetadataRange());
+        lookups.add(be.toMetaRange());
         removeOverlapping(metaCache, be);
       }
 
diff --git a/core/src/main/java/org/apache/accumulo/core/clientImpl/TabletServerBatchReaderIterator.java b/core/src/main/java/org/apache/accumulo/core/clientImpl/TabletServerBatchReaderIterator.java
index 984143f..a80604a 100644
--- a/core/src/main/java/org/apache/accumulo/core/clientImpl/TabletServerBatchReaderIterator.java
+++ b/core/src/main/java/org/apache/accumulo/core/clientImpl/TabletServerBatchReaderIterator.java
@@ -545,7 +545,7 @@ public class TabletServerBatchReaderIterator implements Iterator<Entry<Key,Value
 
     // remove partial scan from unscanned
     if (scanResult.partScan != null) {
-      KeyExtent ke = new KeyExtent(scanResult.partScan);
+      KeyExtent ke = KeyExtent.fromThrift(scanResult.partScan);
       Key nextKey = new Key(scanResult.partNextKey);
 
       ListIterator<Range> iterator = unscanned.get(ke).listIterator();
@@ -640,7 +640,7 @@ public class TabletServerBatchReaderIterator implements Iterator<Entry<Key,Value
       for (Range range : entry.getValue()) {
         ranges.add(new Range(range));
       }
-      unscanned.put(new KeyExtent(entry.getKey()), ranges);
+      unscanned.put(KeyExtent.copyOf(entry.getKey()), ranges);
     }
 
     timeoutTracker.startingScan();
@@ -766,7 +766,7 @@ public class TabletServerBatchReaderIterator implements Iterator<Entry<Key,Value
       log.debug("Server : " + server + " msg : " + e.getMessage(), e);
       String tableInfo = "?";
       if (e.getExtent() != null) {
-        TableId tableId = new KeyExtent(e.getExtent()).getTableId();
+        TableId tableId = KeyExtent.fromThrift(e.getExtent()).tableId();
         tableInfo = Tables.getPrintableTableInfoFromId(context, tableId);
       }
       String message = "Table " + tableInfo + " does not have sampling configured or built";
diff --git a/core/src/main/java/org/apache/accumulo/core/clientImpl/TabletServerBatchWriter.java b/core/src/main/java/org/apache/accumulo/core/clientImpl/TabletServerBatchWriter.java
index ff04bbf..f27df42 100644
--- a/core/src/main/java/org/apache/accumulo/core/clientImpl/TabletServerBatchWriter.java
+++ b/core/src/main/java/org/apache/accumulo/core/clientImpl/TabletServerBatchWriter.java
@@ -500,7 +500,7 @@ public class TabletServerBatchWriter implements AutoCloseable {
       // was a table deleted?
       HashSet<TableId> tableIds = new HashSet<>();
       for (KeyExtent ke : authorizationFailures.keySet())
-        tableIds.add(ke.getTableId());
+        tableIds.add(ke.tableId());
 
       Tables.clearCache(context);
       for (TableId tableId : tableIds)
@@ -602,7 +602,7 @@ public class TabletServerBatchWriter implements AutoCloseable {
 
     synchronized void add(TabletServerMutations<Mutation> tsm) {
       init();
-      tsm.getMutations().forEach((ke, muts) -> recentFailures.addAll(ke.getTableId(), muts));
+      tsm.getMutations().forEach((ke, muts) -> recentFailures.addAll(ke.tableId(), muts));
     }
 
     @Override
@@ -826,7 +826,7 @@ public class TabletServerBatchWriter implements AutoCloseable {
           Set<TableId> tableIds = new TreeSet<>();
           for (Map.Entry<KeyExtent,List<Mutation>> entry : mutationBatch.entrySet()) {
             count += entry.getValue().size();
-            tableIds.add(entry.getKey().getTableId());
+            tableIds.add(entry.getKey().tableId());
           }
 
           String msg = "sending " + String.format("%,d", count) + " mutations to "
@@ -872,7 +872,7 @@ public class TabletServerBatchWriter implements AutoCloseable {
 
           HashSet<TableId> tables = new HashSet<>();
           for (KeyExtent ke : mutationBatch.keySet())
-            tables.add(ke.getTableId());
+            tables.add(ke.tableId());
 
           for (TableId table : tables)
             getLocator(table).invalidateCache(context, location);
@@ -913,8 +913,8 @@ public class TabletServerBatchWriter implements AutoCloseable {
               client.update(tinfo, context.rpcCreds(), entry.getKey().toThrift(),
                   entry.getValue().get(0).toThrift(), DurabilityImpl.toThrift(durability));
             } catch (NotServingTabletException e) {
-              allFailures.addAll(entry.getKey().getTableId(), entry.getValue());
-              getLocator(entry.getKey().getTableId()).invalidateCache(entry.getKey());
+              allFailures.addAll(entry.getKey().tableId(), entry.getValue());
+              getLocator(entry.getKey().tableId()).invalidateCache(entry.getKey());
             } catch (ConstraintViolationException e) {
               updatedConstraintViolations(
                   Translator.translate(e.violationSummaries, Translators.TCVST));
@@ -958,7 +958,7 @@ public class TabletServerBatchWriter implements AutoCloseable {
               int numCommitted = (int) (long) entry.getValue();
               totalCommitted += numCommitted;
 
-              TableId tableId = failedExtent.getTableId();
+              TableId tableId = failedExtent.tableId();
 
               getLocator(tableId).invalidateCache(failedExtent);
 
diff --git a/core/src/main/java/org/apache/accumulo/core/clientImpl/ThriftScanner.java b/core/src/main/java/org/apache/accumulo/core/clientImpl/ThriftScanner.java
index 9a4b87f..646fdbe 100644
--- a/core/src/main/java/org/apache/accumulo/core/clientImpl/ThriftScanner.java
+++ b/core/src/main/java/org/apache/accumulo/core/clientImpl/ThriftScanner.java
@@ -105,7 +105,7 @@ public class ThriftScanner {
       try {
         // not reading whole rows (or stopping on row boundaries) so there is no need to enable
         // isolation below
-        ScanState scanState = new ScanState(context, extent.getTableId(), authorizations, range,
+        ScanState scanState = new ScanState(context, extent.tableId(), authorizations, range,
             fetchedColumns, size, serverSideIteratorList, serverSideIteratorOptions, false,
             Constants.SCANNER_DEFAULT_READAHEAD_THRESHOLD, null, batchTimeOut, classLoaderContext,
             null);
@@ -289,7 +289,7 @@ public class ThriftScanner {
               if (scanState.range.getStartKey() != null
                   && dataRange.afterEndKey(scanState.range.getStartKey())) {
                 // go to the next tablet
-                scanState.startRow = loc.tablet_extent.getEndRow();
+                scanState.startRow = loc.tablet_extent.endRow();
                 scanState.skipStartRow = true;
                 loc = null;
               } else if (scanState.range.getEndKey() != null
@@ -441,7 +441,7 @@ public class ThriftScanner {
 
       if (scanState.scanID == null) {
         Thread.currentThread().setName("Starting scan tserver=" + loc.tablet_location + " tableId="
-            + loc.tablet_extent.getTableId());
+            + loc.tablet_extent.tableId());
 
         if (log.isTraceEnabled()) {
           String msg = "Starting scan tserver=" + loc.tablet_location + " tablet="
@@ -502,7 +502,7 @@ public class ThriftScanner {
       } else {
         // log.debug("No more : tab end row = "+loc.tablet_extent.getEndRow()+" range =
         // "+scanState.range);
-        if (loc.tablet_extent.getEndRow() == null) {
+        if (loc.tablet_extent.endRow() == null) {
           scanState.finished = true;
 
           if (timer != null) {
@@ -513,8 +513,8 @@ public class ThriftScanner {
           }
 
         } else if (scanState.range.getEndKey() == null || !scanState.range
-            .afterEndKey(new Key(loc.tablet_extent.getEndRow()).followingKey(PartialKey.ROW))) {
-          scanState.startRow = loc.tablet_extent.getEndRow();
+            .afterEndKey(new Key(loc.tablet_extent.endRow()).followingKey(PartialKey.ROW))) {
+          scanState.startRow = loc.tablet_extent.endRow();
           scanState.skipStartRow = true;
 
           if (timer != null) {
diff --git a/core/src/main/java/org/apache/accumulo/core/clientImpl/Translator.java b/core/src/main/java/org/apache/accumulo/core/clientImpl/Translator.java
index e212758..bd7473b 100644
--- a/core/src/main/java/org/apache/accumulo/core/clientImpl/Translator.java
+++ b/core/src/main/java/org/apache/accumulo/core/clientImpl/Translator.java
@@ -43,7 +43,7 @@ public abstract class Translator<IT,OT> {
   public static class TKeyExtentTranslator extends Translator<TKeyExtent,KeyExtent> {
     @Override
     public KeyExtent translate(TKeyExtent input) {
-      return new KeyExtent(input);
+      return KeyExtent.fromThrift(input);
     }
 
   }
diff --git a/core/src/main/java/org/apache/accumulo/core/clientImpl/bulk/Bulk.java b/core/src/main/java/org/apache/accumulo/core/clientImpl/bulk/Bulk.java
index 75d0d07..21cef90 100644
--- a/core/src/main/java/org/apache/accumulo/core/clientImpl/bulk/Bulk.java
+++ b/core/src/main/java/org/apache/accumulo/core/clientImpl/bulk/Bulk.java
@@ -221,7 +221,7 @@ public class Bulk {
   }
 
   public static Tablet toTablet(KeyExtent keyExtent) {
-    return new Tablet(keyExtent.getEndRow(), keyExtent.getPrevEndRow());
+    return new Tablet(keyExtent.endRow(), keyExtent.prevEndRow());
   }
 
   public static KeyExtent toKeyExtent(TableId tableId, Tablet tablet) {
diff --git a/core/src/main/java/org/apache/accumulo/core/clientImpl/bulk/BulkImport.java b/core/src/main/java/org/apache/accumulo/core/clientImpl/bulk/BulkImport.java
index 002f192..44fee8f 100644
--- a/core/src/main/java/org/apache/accumulo/core/clientImpl/bulk/BulkImport.java
+++ b/core/src/main/java/org/apache/accumulo/core/clientImpl/bulk/BulkImport.java
@@ -340,7 +340,7 @@ public class BulkImport implements ImportDestinationArguments, ImportMappingOpti
       KeyExtent extent = extentCache.lookup(row);
       // log.debug(filename + " found row " + row + " at location " + tabletLocation);
       result.add(extent);
-      row = extent.getEndRow();
+      row = extent.endRow();
       if (row != null && (endRow == null || row.compareTo(endRow) < 0)) {
         row = nextRow(row);
       } else
@@ -467,8 +467,8 @@ public class BulkImport implements ImportDestinationArguments, ImportMappingOpti
 
         extents.add(extent);
 
-        while (!extent.contains(endRow) && extent.getEndRow() != null) {
-          extent = kec.lookup(nextRow(extent.getEndRow()));
+        while (!extent.contains(endRow) && extent.endRow() != null) {
+          extent = kec.lookup(nextRow(extent.endRow()));
           extents.add(extent);
         }
 
diff --git a/core/src/main/java/org/apache/accumulo/core/clientImpl/bulk/ConcurrentKeyExtentCache.java b/core/src/main/java/org/apache/accumulo/core/clientImpl/bulk/ConcurrentKeyExtentCache.java
index d343294..c31695c 100644
--- a/core/src/main/java/org/apache/accumulo/core/clientImpl/bulk/ConcurrentKeyExtentCache.java
+++ b/core/src/main/java/org/apache/accumulo/core/clientImpl/bulk/ConcurrentKeyExtentCache.java
@@ -73,14 +73,14 @@ class ConcurrentKeyExtentCache implements KeyExtentCache {
   }
 
   private boolean inCache(KeyExtent e) {
-    return Objects.equals(e, extents.get(e.getEndRow() == null ? MAX : e.getEndRow()));
+    return Objects.equals(e, extents.get(e.endRow() == null ? MAX : e.endRow()));
   }
 
   @VisibleForTesting
   protected void updateCache(KeyExtent e) {
-    Text prevRow = e.getPrevEndRow() == null ? new Text() : e.getPrevEndRow();
-    Text endRow = e.getEndRow() == null ? MAX : e.getEndRow();
-    extents.subMap(prevRow, e.getPrevEndRow() == null, endRow, true).clear();
+    Text prevRow = e.prevEndRow() == null ? new Text() : e.prevEndRow();
+    Text endRow = e.endRow() == null ? MAX : e.endRow();
+    extents.subMap(prevRow, e.prevEndRow() == null, endRow, true).clear();
     extents.put(endRow, e);
   }
 
diff --git a/core/src/main/java/org/apache/accumulo/core/clientImpl/mapreduce/lib/InputConfigurator.java b/core/src/main/java/org/apache/accumulo/core/clientImpl/mapreduce/lib/InputConfigurator.java
index 4e35185..271be77 100644
--- a/core/src/main/java/org/apache/accumulo/core/clientImpl/mapreduce/lib/InputConfigurator.java
+++ b/core/src/main/java/org/apache/accumulo/core/clientImpl/mapreduce/lib/InputConfigurator.java
@@ -845,7 +845,7 @@ public class InputConfigurator extends ConfiguratorBase {
         startRow = new Text();
 
       Range metadataRange =
-          new Range(new KeyExtent(tableId, startRow, null).getMetadataEntry(), true, null, false);
+          new Range(new KeyExtent(tableId, startRow, null).toMetaRow(), true, null, false);
       Scanner scanner = context.createScanner(MetadataTable.NAME, Authorizations.EMPTY);
       TabletColumnFamily.PREV_ROW_COLUMN.fetch(scanner);
       scanner.fetchColumnFamily(LastLocationColumnFamily.NAME);
@@ -875,7 +875,7 @@ public class InputConfigurator extends ConfiguratorBase {
           }
 
           if (TabletColumnFamily.PREV_ROW_COLUMN.hasColumns(key)) {
-            extent = new KeyExtent(key.getRow(), entry.getValue());
+            extent = KeyExtent.fromMetaPrevRow(entry);
           }
 
         }
@@ -883,7 +883,7 @@ public class InputConfigurator extends ConfiguratorBase {
         if (location != null)
           return null;
 
-        if (!extent.getTableId().equals(tableId)) {
+        if (!extent.tableId().equals(tableId)) {
           throw new AccumuloException("Saw unexpected table Id " + tableId + " " + extent);
         }
 
@@ -894,8 +894,8 @@ public class InputConfigurator extends ConfiguratorBase {
         binnedRanges.computeIfAbsent(last, k -> new HashMap<>())
             .computeIfAbsent(extent, k -> new ArrayList<>()).add(range);
 
-        if (extent.getEndRow() == null
-            || range.afterEndKey(new Key(extent.getEndRow()).followingKey(PartialKey.ROW))) {
+        if (extent.endRow() == null
+            || range.afterEndKey(new Key(extent.endRow()).followingKey(PartialKey.ROW))) {
           break;
         }
 
diff --git a/core/src/main/java/org/apache/accumulo/core/data/Range.java b/core/src/main/java/org/apache/accumulo/core/data/Range.java
index 6248184..57405b1 100644
--- a/core/src/main/java/org/apache/accumulo/core/data/Range.java
+++ b/core/src/main/java/org/apache/accumulo/core/data/Range.java
@@ -124,7 +124,7 @@ public class Range implements WritableComparable<Range> {
    * @param endRow
    *          ending row; set to null for positive infinity
    * @param endRowInclusive
-   *          true to include start row, false to skip
+   *          true to include end row, false to skip
    * @throws IllegalArgumentException
    *           if end row is before start row
    */
diff --git a/core/src/main/java/org/apache/accumulo/core/dataImpl/KeyExtent.java b/core/src/main/java/org/apache/accumulo/core/dataImpl/KeyExtent.java
index 6c61983..220e52e 100644
--- a/core/src/main/java/org/apache/accumulo/core/dataImpl/KeyExtent.java
+++ b/core/src/main/java/org/apache/accumulo/core/dataImpl/KeyExtent.java
@@ -19,6 +19,7 @@
 package org.apache.accumulo.core.dataImpl;
 
 import static java.nio.charset.StandardCharsets.UTF_8;
+import static java.util.Objects.requireNonNull;
 
 import java.io.ByteArrayOutputStream;
 import java.io.DataInput;
@@ -26,7 +27,6 @@ import java.io.DataOutput;
 import java.io.DataOutputStream;
 import java.io.IOException;
 import java.nio.ByteBuffer;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.Map.Entry;
@@ -37,8 +37,7 @@ import java.util.SortedSet;
 import java.util.TreeSet;
 import java.util.UUID;
 
-import org.apache.accumulo.core.data.ByteSequence;
-import org.apache.accumulo.core.data.Mutation;
+import org.apache.accumulo.core.data.Key;
 import org.apache.accumulo.core.data.Range;
 import org.apache.accumulo.core.data.TableId;
 import org.apache.accumulo.core.data.Value;
@@ -48,312 +47,234 @@ import org.apache.accumulo.core.metadata.RootTable;
 import org.apache.accumulo.core.metadata.schema.MetadataSchema.TabletsSection;
 import org.apache.accumulo.core.metadata.schema.MetadataSchema.TabletsSection.TabletColumnFamily;
 import org.apache.accumulo.core.util.ByteBufferUtil;
+import org.apache.accumulo.core.util.Pair;
 import org.apache.accumulo.core.util.TextUtil;
 import org.apache.hadoop.io.BinaryComparable;
 import org.apache.hadoop.io.Text;
-import org.apache.hadoop.io.WritableComparable;
 
 /**
  * keeps track of information needed to identify a tablet
  */
-public class KeyExtent implements WritableComparable<KeyExtent> {
+public class KeyExtent implements Comparable<KeyExtent> {
 
-  private TableId tableId;
-  private Text textEndRow;
-  private Text textPrevEndRow;
+  private final TableId tableId;
+  private final Text endRow;
+  private final Text prevEndRow;
 
-  private static final TableId EMPTY_ID = TableId.of("");
-  private static final Text EMPTY_TEXT = new Text("");
-
-  private void check() {
+  // lazily computed, as needed
+  private volatile int hashCode = 0;
 
-    if (getTableId() == null)
-      throw new IllegalArgumentException("null table id not allowed");
+  private static final Text EMPTY_TEXT = new Text("");
 
-    if (getEndRow() == null || getPrevEndRow() == null)
-      return;
+  // The last tablet in a table has no end row, so null sorts last for end row; similarly, the first
+  // tablet has no previous end row, so null sorts first for previous end row
+  private static final Comparator<KeyExtent> COMPARATOR = Comparator.comparing(KeyExtent::tableId)
+      .thenComparing(KeyExtent::endRow, Comparator.nullsLast(Text::compareTo))
+      .thenComparing(KeyExtent::prevEndRow, Comparator.nullsFirst(Text::compareTo));
 
-    if (getPrevEndRow().compareTo(getEndRow()) >= 0) {
+  /**
+   * Create a new KeyExtent from its components.
+   *
+   * @param table
+   *          the ID for the table
+   * @param endRow
+   *          the last row in this tablet, or null if this is the last tablet in this table
+   * @param prevEndRow
+   *          the last row in the immediately preceding tablet for the table, or null if this
+   *          represents the first tablet in this table
+   */
+  public KeyExtent(TableId table, Text endRow, Text prevEndRow) {
+    tableId = requireNonNull(table, "null table ID not allowed");
+    if (endRow != null && prevEndRow != null && prevEndRow.compareTo(endRow) >= 0) {
       throw new IllegalArgumentException(
-          "prevEndRow (" + getPrevEndRow() + ") >= endRow (" + getEndRow() + ")");
+          "prevEndRow (" + prevEndRow + ") >= endRow (" + endRow + ")");
     }
+    this.endRow = endRow == null ? null : new Text(endRow);
+    this.prevEndRow = prevEndRow == null ? null : new Text(prevEndRow);
   }
 
   /**
-   * Default constructor
+   * Create a copy of a provided KeyExtent.
    *
+   * @param original
+   *          the KeyExtent to copy
    */
-  public KeyExtent() {
-    this.setTableId(EMPTY_ID);
-    this.setEndRow(new Text(), false, false);
-    this.setPrevEndRow(new Text(), false, false);
-  }
-
-  public KeyExtent(TableId table, Text endRow, Text prevEndRow) {
-    this.setTableId(table);
-    this.setEndRow(endRow, false, true);
-    this.setPrevEndRow(prevEndRow, false, true);
-
-    check();
-  }
-
-  public KeyExtent(KeyExtent extent) {
-    // extent has already deduped table id, so there is no need to do it again
-    this.tableId = extent.tableId;
-    this.setEndRow(extent.getEndRow(), false, true);
-    this.setPrevEndRow(extent.getPrevEndRow(), false, true);
-
-    check();
-  }
-
-  public KeyExtent(TKeyExtent tke) {
-    this.setTableId(TableId.of(new String(ByteBufferUtil.toBytes(tke.table), UTF_8)));
-    this.setEndRow(tke.endRow == null ? null : new Text(ByteBufferUtil.toBytes(tke.endRow)), false,
-        false);
-    this.setPrevEndRow(
-        tke.prevEndRow == null ? null : new Text(ByteBufferUtil.toBytes(tke.prevEndRow)), false,
-        false);
-
-    check();
+  public static KeyExtent copyOf(KeyExtent original) {
+    return new KeyExtent(original.tableId(), original.endRow(), original.prevEndRow());
   }
 
   /**
-   * Returns a String representing this extent's entry in the Metadata table
+   * Create a KeyExtent from its Thrift form.
    *
+   * @param tke
+   *          the KeyExtent in its Thrift object form
    */
-  public Text getMetadataEntry() {
-    return TabletsSection.getRow(getTableId(), getEndRow());
+  public static KeyExtent fromThrift(TKeyExtent tke) {
+    TableId tableId = TableId.of(new String(ByteBufferUtil.toBytes(tke.table), UTF_8));
+    Text endRow = tke.endRow == null ? null : new Text(ByteBufferUtil.toBytes(tke.endRow));
+    Text prevEndRow =
+        tke.prevEndRow == null ? null : new Text(ByteBufferUtil.toBytes(tke.prevEndRow));
+    return new KeyExtent(tableId, endRow, prevEndRow);
   }
 
-  // constructor for loading extents from metadata rows
-  public KeyExtent(Text flattenedExtent, Value prevEndRow) {
-    decodeMetadataRow(flattenedExtent);
-
-    // decode the prev row
-    this.setPrevEndRow(decodePrevEndRow(prevEndRow), false, true);
-
-    check();
+  /**
+   * Convert to Thrift form.
+   */
+  public TKeyExtent toThrift() {
+    return new TKeyExtent(ByteBuffer.wrap(tableId().canonical().getBytes(UTF_8)),
+        endRow() == null ? null : TextUtil.getByteBuffer(endRow()),
+        prevEndRow() == null ? null : TextUtil.getByteBuffer(prevEndRow()));
   }
 
-  // recreates an encoded extent from a string representation
-  // this encoding is what is stored as the row id of the metadata table
-  public KeyExtent(Text flattenedExtent, Text prevEndRow) {
-
-    decodeMetadataRow(flattenedExtent);
-
-    this.setPrevEndRow(null, false, false);
-    if (prevEndRow != null)
-      this.setPrevEndRow(prevEndRow, false, true);
-
-    check();
+  /**
+   * Create a KeyExtent from a metadata previous end row entry.
+   *
+   * @param prevRowEntry
+   *          a provided previous end row entry from the metadata table, stored in the
+   *          <code>{@value TabletColumnFamily#STR_NAME}</code> column family and
+   *          <code>{@value TabletColumnFamily#PREV_ROW_QUAL}</code> column. If the individual
+   *          components are needed, consider {@link #KeyExtent(TableId, Text, Text)} or
+   *          {@link #fromMetaRow(Text, Text)} instead.
+   */
+  public static KeyExtent fromMetaPrevRow(Entry<Key,Value> prevRowEntry) {
+    return fromMetaRow(prevRowEntry.getKey().getRow(),
+        TabletColumnFamily.decodePrevEndRow(prevRowEntry.getValue()));
   }
 
   /**
-   * Sets the extents table id
+   * Create a KeyExtent from the table ID and the end row encoded in the row field of a tablet's
+   * metadata entry, with no previous end row.
    *
+   * @param encodedMetadataRow
+   *          the encoded <code>tableId</code> and <code>endRow</code> from a metadata entry, as in
+   *          <code>entry.getKey().getRow()</code> or from
+   *          {@link TabletsSection#encodeRow(TableId, Text)}
    */
-  public void setTableId(TableId tId) {
-    Objects.requireNonNull(tId, "null table id not allowed");
-
-    this.tableId = tId;
-
-    hashCode = 0;
+  public static KeyExtent fromMetaRow(Text encodedMetadataRow) {
+    return fromMetaRow(encodedMetadataRow, (Text) null);
   }
 
   /**
-   * Returns the extent's table id
+   * Create a KeyExtent from the table ID and the end row encoded in the row field of a tablet's
+   * metadata entry, along with a previous end row.
    *
+   * @param encodedMetadataRow
+   *          the encoded <code>tableId</code> and <code>endRow</code> from a metadata entry, as in
+   *          <code>entry.getKey().getRow()</code> or from
+   *          {@link TabletsSection#encodeRow(TableId, Text)}
+   * @param prevEndRow
+   *          the unencoded previous end row (a copy will be made)
    */
-  public TableId getTableId() {
-    return tableId;
+  public static KeyExtent fromMetaRow(Text encodedMetadataRow, Text prevEndRow) {
+    Pair<TableId,Text> tableIdAndEndRow = TabletsSection.decodeRow(encodedMetadataRow);
+    TableId tableId = tableIdAndEndRow.getFirst();
+    Text endRow = tableIdAndEndRow.getSecond();
+    return new KeyExtent(tableId, endRow, prevEndRow);
   }
 
-  private void setEndRow(Text endRow, boolean check, boolean copy) {
-    if (endRow != null)
-      if (copy)
-        this.textEndRow = new Text(endRow);
-      else
-        this.textEndRow = endRow;
-    else
-      this.textEndRow = null;
-
-    hashCode = 0;
-    if (check)
-      check();
+  /**
+   * Return a serialized form of the table ID and end row for this extent, in a form suitable for
+   * use in the row portion of metadata entries for the tablet this extent represents.
+   */
+  public Text toMetaRow() {
+    return TabletsSection.encodeRow(tableId(), endRow());
   }
 
   /**
-   * Sets this extent's end row
-   *
+   * Return the extent's table ID.
    */
-  public void setEndRow(Text endRow) {
-    setEndRow(endRow, true, true);
+  public TableId tableId() {
+    return tableId;
   }
 
   /**
    * Returns this extent's end row
-   *
    */
-  public Text getEndRow() {
-    return textEndRow;
+  public Text endRow() {
+    return endRow;
   }
 
   /**
    * Return the previous extent's end row
-   *
    */
-  public Text getPrevEndRow() {
-    return textPrevEndRow;
-  }
-
-  private void setPrevEndRow(Text prevEndRow, boolean check, boolean copy) {
-    if (prevEndRow != null)
-      if (copy)
-        this.textPrevEndRow = new Text(prevEndRow);
-      else
-        this.textPrevEndRow = prevEndRow;
-    else
-      this.textPrevEndRow = null;
-
-    hashCode = 0;
-    if (check)
-      check();
+  public Text prevEndRow() {
+    return prevEndRow;
   }
 
   /**
-   * Sets the previous extent's end row
+   * Create a KeyExtent from a serialized form.
    *
+   * @see #writeTo(DataOutput)
    */
-  public void setPrevEndRow(Text prevEndRow) {
-    setPrevEndRow(prevEndRow, true, true);
-  }
-
-  @Override
-  public void readFields(DataInput in) throws IOException {
+  public static KeyExtent readFrom(DataInput in) throws IOException {
     Text tid = new Text();
     tid.readFields(in);
-    setTableId(TableId.of(tid.toString()));
+    TableId tableId = TableId.of(tid.toString());
+    Text endRow = null;
+    Text prevEndRow = null;
     boolean hasRow = in.readBoolean();
     if (hasRow) {
-      Text er = new Text();
-      er.readFields(in);
-      setEndRow(er, false, false);
-    } else {
-      setEndRow(null, false, false);
+      endRow = new Text();
+      endRow.readFields(in);
     }
     boolean hasPrevRow = in.readBoolean();
     if (hasPrevRow) {
-      Text per = new Text();
-      per.readFields(in);
-      setPrevEndRow(per, false, true);
-    } else {
-      setPrevEndRow(null);
+      prevEndRow = new Text();
+      prevEndRow.readFields(in);
     }
-
-    hashCode = 0;
-    check();
+    return new KeyExtent(tableId, endRow, prevEndRow);
   }
 
-  @Override
-  public void write(DataOutput out) throws IOException {
-    new Text(getTableId().canonical()).write(out);
-    if (getEndRow() != null) {
+  /**
+   * Serialize this KeyExtent.
+   *
+   * @see #readFrom(DataInput)
+   */
+  public void writeTo(DataOutput out) throws IOException {
+    new Text(tableId().canonical()).write(out);
+    if (endRow() != null) {
       out.writeBoolean(true);
-      getEndRow().write(out);
+      endRow().write(out);
     } else {
       out.writeBoolean(false);
     }
-    if (getPrevEndRow() != null) {
+    if (prevEndRow() != null) {
       out.writeBoolean(true);
-      getPrevEndRow().write(out);
+      prevEndRow().write(out);
     } else {
       out.writeBoolean(false);
     }
   }
 
-  /**
-   * Returns a String representing the previous extent's entry in the Metadata table
-   *
-   */
-  public Mutation getPrevRowUpdateMutation() {
-    return getPrevRowUpdateMutation(this);
-  }
-
-  public static Text decodePrevEndRow(Value ibw) {
-    Text per = null;
-
-    if (ibw.get()[0] != 0) {
-      per = new Text();
-      per.set(ibw.get(), 1, ibw.get().length - 1);
-    }
-
-    return per;
-  }
-
-  public static Value encodePrevEndRow(Text per) {
-    if (per == null)
-      return new Value(new byte[] {0});
-    byte[] b = new byte[per.getLength() + 1];
-    b[0] = 1;
-    System.arraycopy(per.getBytes(), 0, b, 1, per.getLength());
-    return new Value(b);
-  }
-
-  public static Mutation getPrevRowUpdateMutation(KeyExtent ke) {
-    Mutation m = new Mutation(ke.getMetadataEntry());
-    TabletColumnFamily.PREV_ROW_COLUMN.put(m, encodePrevEndRow(ke.getPrevEndRow()));
-    return m;
-  }
-
-  // The last tablet in a table has no end row, so null sorts last for end row; similarly, the first
-  // tablet has no previous end row, so null sorts first for previous end row
-  private static final Comparator<KeyExtent> COMPARATOR =
-      Comparator.comparing(KeyExtent::getTableId)
-          .thenComparing(KeyExtent::getEndRow, Comparator.nullsLast(Text::compareTo))
-          .thenComparing(KeyExtent::getPrevEndRow, Comparator.nullsFirst(Text::compareTo));
-
   @Override
   public int compareTo(KeyExtent other) {
     return COMPARATOR.compare(this, other);
   }
 
-  private int hashCode = 0;
-
   @Override
   public int hashCode() {
-    if (hashCode != 0)
+    // lazily compute hash code, if needed
+    if (hashCode != 0) {
       return hashCode;
-
-    int prevEndRowHash = 0;
-    int endRowHash = 0;
-    if (this.getEndRow() != null) {
-      endRowHash = this.getEndRow().hashCode();
-    }
-
-    if (this.getPrevEndRow() != null) {
-      prevEndRowHash = this.getPrevEndRow().hashCode();
     }
-
-    hashCode = getTableId().hashCode() + endRowHash + prevEndRowHash;
+    int tmpHashCode = tableId().hashCode();
+    tmpHashCode += endRow() == null ? 0 : endRow().hashCode();
+    tmpHashCode += prevEndRow() == null ? 0 : prevEndRow().hashCode();
+    hashCode = tmpHashCode;
     return hashCode;
   }
 
-  private boolean equals(Text t1, Text t2) {
-    if (t1 == null || t2 == null)
-      return t1 == t2;
-
-    return t1.equals(t2);
-  }
-
   @Override
   public boolean equals(Object o) {
-    if (o == this)
+    if (o == this) {
       return true;
-    if (!(o instanceof KeyExtent))
+    }
+    if (!(o instanceof KeyExtent)) {
       return false;
+    }
     KeyExtent oke = (KeyExtent) o;
-    return tableId.equals(oke.tableId) && equals(textEndRow, oke.textEndRow)
-        && equals(textPrevEndRow, oke.textPrevEndRow);
+    return tableId().equals(oke.tableId()) && Objects.equals(endRow(), oke.endRow())
+        && Objects.equals(prevEndRow(), oke.prevEndRow());
   }
 
   @Override
@@ -361,251 +282,135 @@ public class KeyExtent implements WritableComparable<KeyExtent> {
     String endRowString;
     String prevEndRowString;
     String tableIdString =
-        getTableId().canonical().replaceAll(";", "\\\\;").replaceAll("\\\\", "\\\\\\\\");
+        tableId().canonical().replaceAll(";", "\\\\;").replaceAll("\\\\", "\\\\\\\\");
 
-    if (getEndRow() == null)
+    if (endRow() == null) {
       endRowString = "<";
-    else
-      endRowString = ";" + TextUtil.truncate(getEndRow()).toString().replaceAll(";", "\\\\;")
+    } else {
+      endRowString = ";" + TextUtil.truncate(endRow()).toString().replaceAll(";", "\\\\;")
           .replaceAll("\\\\", "\\\\\\\\");
+    }
 
-    if (getPrevEndRow() == null)
+    if (prevEndRow() == null) {
       prevEndRowString = "<";
-    else
-      prevEndRowString = ";" + TextUtil.truncate(getPrevEndRow()).toString()
-          .replaceAll(";", "\\\\;").replaceAll("\\\\", "\\\\\\\\");
+    } else {
+      prevEndRowString = ";" + TextUtil.truncate(prevEndRow()).toString().replaceAll(";", "\\\\;")
+          .replaceAll("\\\\", "\\\\\\\\");
+    }
 
     return tableIdString + endRowString + prevEndRowString;
   }
 
+  /**
+   * Retrieve a unique identifier for this tablet that is useful for logging, without revealing the
+   * contents of the end row and previous end row.
+   */
   public UUID getUUID() {
-    try {
-
-      ByteArrayOutputStream baos = new ByteArrayOutputStream();
-      DataOutputStream dos = new DataOutputStream(baos);
-
+    try (var baos = new ByteArrayOutputStream(); var dos = new DataOutputStream(baos)) {
       // to get a unique hash it is important to encode the data
       // like it is being serialized
-
-      this.write(dos);
-
-      dos.close();
-
+      writeTo(dos);
       return UUID.nameUUIDFromBytes(baos.toByteArray());
-
-    } catch (IOException e) {
-      // should not happen since we are writing to memory
-      throw new RuntimeException(e);
+    } catch (IOException impossible) {
+      // impossible when ByteArrayOutputStream is backing the DataOutputStream
+      throw new AssertionError(impossible);
     }
   }
 
-  // note: this is only the encoding of the table id and the last row, not the prev row
   /**
-   * Populates the extent's fields based on a flatted extent
+   * Determine if another KeyExtent is wholly contained within the range of this one. * @param oke
    *
+   * @return true if and only if the provided KeyExtent is contained within the range of this one
    */
-  private void decodeMetadataRow(Text flattenedExtent) {
-    int semiPos = -1;
-    int ltPos = -1;
-
-    for (int i = 0; i < flattenedExtent.getLength(); i++) {
-      if (flattenedExtent.getBytes()[i] == ';' && semiPos < 0) {
-        // want the position of the first semicolon
-        semiPos = i;
-      }
-
-      if (flattenedExtent.getBytes()[i] == '<') {
-        ltPos = i;
-      }
-    }
-
-    if (semiPos < 0 && ltPos < 0) {
-      throw new IllegalArgumentException(
-          "Metadata row does not contain ; or <  " + flattenedExtent);
-    }
-
-    if (semiPos < 0) {
-
-      if (ltPos != flattenedExtent.getLength() - 1) {
-        throw new IllegalArgumentException(
-            "< must come at end of Metadata row  " + flattenedExtent);
-      }
-
-      String decodedString = new String(
-          Arrays.copyOfRange(flattenedExtent.getBytes(), 0, flattenedExtent.getLength() - 1),
-          UTF_8);
-      TableId tableId = TableId.of(decodedString);
-      this.setTableId(tableId);
-      this.setEndRow(null, false, false);
-    } else {
-
-      TableId tableId =
-          TableId.of(new String(Arrays.copyOfRange(flattenedExtent.getBytes(), 0, semiPos), UTF_8));
-
-      Text endRow = new Text();
-      endRow.set(flattenedExtent.getBytes(), semiPos + 1,
-          flattenedExtent.getLength() - (semiPos + 1));
-
-      this.setTableId(tableId);
-
-      this.setEndRow(endRow, false, false);
-    }
-  }
-
-  public static TableId tableOfMetadataRow(Text row) {
-    KeyExtent ke = new KeyExtent();
-    ke.decodeMetadataRow(row);
-    return ke.getTableId();
-  }
-
   public boolean contains(KeyExtent oke) {
-    boolean containsPrevRow = getPrevEndRow() == null
-        || (oke.getPrevEndRow() != null && getPrevEndRow().compareTo(oke.getPrevEndRow()) <= 0);
-    boolean containsEndRow = getEndRow() == null
-        || (oke.getEndRow() != null && getEndRow().compareTo(oke.getEndRow()) >= 0);
+    // true if this prev row is before the other
+    boolean containsPrevRow = prevEndRow() == null
+        || (oke.prevEndRow() != null && prevEndRow().compareTo(oke.prevEndRow()) <= 0);
+    // true if this end row is after the other
+    boolean containsEndRow =
+        endRow() == null || (oke.endRow() != null && endRow().compareTo(oke.endRow()) >= 0);
     return containsPrevRow && containsEndRow;
   }
 
-  public boolean contains(final ByteSequence bsrow) {
-    if (bsrow == null) {
-      throw new IllegalArgumentException(
-          "Passing null to contains is ambiguous, could be in first or last extent of table");
-    }
-
-    BinaryComparable row = new BinaryComparable() {
-
-      @Override
-      public int getLength() {
-        return bsrow.length();
-      }
-
-      @Override
-      public byte[] getBytes() {
-        if (bsrow.isBackedByArray() && bsrow.offset() == 0)
-          return bsrow.getBackingArray();
-
-        return bsrow.toArray();
-      }
-    };
-
-    return (this.getPrevEndRow() == null || this.getPrevEndRow().compareTo(row) < 0)
-        && (this.getEndRow() == null || this.getEndRow().compareTo(row) >= 0);
-  }
-
+  /**
+   * Determine if the provided row is contained within the range of this KeyExtent.
+   *
+   * @return true if and only if the provided row is contained within the range of this one
+   */
   public boolean contains(BinaryComparable row) {
     if (row == null) {
       throw new IllegalArgumentException(
           "Passing null to contains is ambiguous, could be in first or last extent of table");
     }
-
-    return (this.getPrevEndRow() == null || this.getPrevEndRow().compareTo(row) < 0)
-        && (this.getEndRow() == null || this.getEndRow().compareTo(row) >= 0);
+    return (prevEndRow() == null || prevEndRow().compareTo(row) < 0)
+        && (endRow() == null || endRow().compareTo(row) >= 0);
   }
 
+  /**
+   * Compute a representation of this extent as a Range suitable for scanning this extent's table
+   * and retrieving all data between this extent's previous end row (exclusive) and its end row
+   * (inclusive) in that table (or another table in the same range, since the returned range does
+   * not specify the table to scan).
+   *
+   * <p>
+   * For example, if this extent represented a range of data from <code>A</code> to <code>Z</code>
+   * for table <code>T</code>, the resulting Range could be used to scan table <code>T</code>'s data
+   * in the exclusive-inclusive range <code>(A,Z]</code>, or the same range in another table,
+   * <code>T2</code>.
+   */
   public Range toDataRange() {
-    return new Range(getPrevEndRow(), false, getEndRow(), true);
+    return new Range(prevEndRow(), false, endRow(), true);
   }
 
-  public Range toMetadataRange() {
-
+  /**
+   * Compute a representation of this extent as a Range suitable for scanning the corresponding
+   * metadata table for this extent's table, and retrieving all the metadata for the table's tablets
+   * between this extent's previous end row (exclusive) and its end row (inclusive) in that table.
+   *
+   * <p>
+   * For example, if this extent represented a range of data from <code>A</code> to <code>Z</code>
+   * for a user table, <code>T</code>, this would compute the range to scan
+   * <code>accumulo.metadata</code> that would include all the the metadata for <code>T</code>'s
+   * tablets that contain data in the range <code>(A,Z]</code>.
+   */
+  public Range toMetaRange() {
     Text metadataPrevRow =
-        TabletsSection.getRow(getTableId(), getPrevEndRow() == null ? EMPTY_TEXT : getPrevEndRow());
-
-    return new Range(metadataPrevRow, getPrevEndRow() == null, getMetadataEntry(), true);
+        TabletsSection.encodeRow(tableId(), prevEndRow() == null ? EMPTY_TEXT : prevEndRow());
+    return new Range(metadataPrevRow, prevEndRow() == null, toMetaRow(), true);
   }
 
-  public static SortedSet<KeyExtent> findChildren(KeyExtent ke, SortedSet<KeyExtent> tablets) {
-
-    SortedSet<KeyExtent> children = null;
-
-    for (KeyExtent tabletKe : tablets) {
-
-      if (ke.getPrevEndRow() == tabletKe.getPrevEndRow()
-          || ke.getPrevEndRow() != null && tabletKe.getPrevEndRow() != null
-              && tabletKe.getPrevEndRow().compareTo(ke.getPrevEndRow()) == 0) {
-        children = new TreeSet<>();
-      }
-
-      if (children != null) {
-        children.add(tabletKe);
-      }
-
-      if (ke.getEndRow() == tabletKe.getEndRow() || ke.getEndRow() != null
-          && tabletKe.getEndRow() != null && tabletKe.getEndRow().compareTo(ke.getEndRow()) == 0) {
-        return children;
-      }
-    }
-
-    return new TreeSet<>();
-  }
-
-  public static KeyExtent findContainingExtent(KeyExtent extent, SortedSet<KeyExtent> extents) {
-
-    KeyExtent lookupExtent = new KeyExtent(extent);
-    lookupExtent.setPrevEndRow(null);
-
-    SortedSet<KeyExtent> tailSet = extents.tailSet(lookupExtent);
-
-    if (tailSet.isEmpty()) {
-      return null;
-    }
-
-    KeyExtent first = tailSet.first();
-
-    if (first.getTableId().compareTo(extent.getTableId()) != 0) {
-      return null;
-    }
-
-    if (first.getPrevEndRow() == null) {
-      return first;
-    }
-
-    if (extent.getPrevEndRow() == null) {
-      return null;
-    }
-
-    if (extent.getPrevEndRow().compareTo(first.getPrevEndRow()) >= 0)
-      return first;
-    return null;
-  }
-
-  private static boolean startsAfter(KeyExtent nke, KeyExtent ke) {
-
-    int tiCmp = ke.getTableId().compareTo(nke.getTableId());
-
-    if (tiCmp > 0) {
-      return true;
-    }
-
-    return ke.getPrevEndRow() != null && nke.getEndRow() != null
-        && ke.getPrevEndRow().compareTo(nke.getEndRow()) >= 0;
+  private boolean startsAfter(KeyExtent other) {
+    KeyExtent nke = requireNonNull(other);
+    return tableId().compareTo(nke.tableId()) > 0 || (prevEndRow() != null && nke.endRow() != null
+        && prevEndRow().compareTo(nke.endRow()) >= 0);
   }
 
   private static Text rowAfterPrevRow(KeyExtent nke) {
-    Text row = new Text(nke.getPrevEndRow());
+    Text row = new Text(nke.prevEndRow());
     row.append(new byte[] {0}, 0, 1);
     return row;
   }
 
   // Some duplication with TabletLocatorImpl
   public static Set<KeyExtent> findOverlapping(KeyExtent nke, SortedSet<KeyExtent> extents) {
-    if (nke == null || extents == null || extents.isEmpty())
+    if (nke == null || extents == null || extents.isEmpty()) {
       return Collections.emptySet();
+    }
 
     SortedSet<KeyExtent> start;
 
-    if (nke.getPrevEndRow() != null) {
+    if (nke.prevEndRow() != null) {
       Text row = rowAfterPrevRow(nke);
-      KeyExtent lookupKey = new KeyExtent(nke.getTableId(), row, null);
+      KeyExtent lookupKey = new KeyExtent(nke.tableId(), row, null);
       start = extents.tailSet(lookupKey);
     } else {
-      KeyExtent lookupKey = new KeyExtent(nke.getTableId(), new Text(), null);
+      KeyExtent lookupKey = new KeyExtent(nke.tableId(), new Text(), null);
       start = extents.tailSet(lookupKey);
     }
 
     TreeSet<KeyExtent> result = new TreeSet<>();
     for (KeyExtent ke : start) {
-      if (startsAfter(nke, ke)) {
+      if (ke.startsAfter(nke)) {
         break;
       }
       result.add(ke);
@@ -621,24 +426,25 @@ public class KeyExtent implements WritableComparable<KeyExtent> {
 
   // Specialization of findOverlapping(KeyExtent, SortedSet<KeyExtent> to work with SortedMap
   public static Set<KeyExtent> findOverlapping(KeyExtent nke, SortedMap<KeyExtent,?> extents) {
-    if (nke == null || extents == null || extents.isEmpty())
+    if (nke == null || extents == null || extents.isEmpty()) {
       return Collections.emptySet();
+    }
 
     SortedMap<KeyExtent,?> start;
 
-    if (nke.getPrevEndRow() != null) {
+    if (nke.prevEndRow() != null) {
       Text row = rowAfterPrevRow(nke);
-      KeyExtent lookupKey = new KeyExtent(nke.getTableId(), row, null);
+      KeyExtent lookupKey = new KeyExtent(nke.tableId(), row, null);
       start = extents.tailMap(lookupKey);
     } else {
-      KeyExtent lookupKey = new KeyExtent(nke.getTableId(), new Text(), null);
+      KeyExtent lookupKey = new KeyExtent(nke.tableId(), new Text(), null);
       start = extents.tailMap(lookupKey);
     }
 
     TreeSet<KeyExtent> result = new TreeSet<>();
     for (Entry<KeyExtent,?> entry : start.entrySet()) {
       KeyExtent ke = entry.getKey();
-      if (startsAfter(nke, ke)) {
+      if (ke.startsAfter(nke)) {
         break;
       }
       result.add(ke);
@@ -646,37 +452,24 @@ public class KeyExtent implements WritableComparable<KeyExtent> {
     return result;
   }
 
-  public static Text getMetadataEntry(KeyExtent extent) {
-    return TabletsSection.getRow(extent.getTableId(), extent.getEndRow());
-  }
-
-  public TKeyExtent toThrift() {
-    return new TKeyExtent(ByteBuffer.wrap(tableId.canonical().getBytes(UTF_8)),
-        textEndRow == null ? null : TextUtil.getByteBuffer(textEndRow),
-        textPrevEndRow == null ? null : TextUtil.getByteBuffer(textPrevEndRow));
-  }
-
   public boolean isPreviousExtent(KeyExtent prevExtent) {
-    if (prevExtent == null)
-      return getPrevEndRow() == null;
-
-    if (!prevExtent.getTableId().equals(getTableId()))
+    if (prevExtent == null) {
+      return prevEndRow() == null;
+    }
+    if (!prevExtent.tableId().equals(tableId())) {
       throw new IllegalArgumentException("Cannot compare across tables " + prevExtent + " " + this);
-
-    if (prevExtent.getEndRow() == null)
-      return false;
-
-    if (getPrevEndRow() == null)
+    }
+    if (prevExtent.endRow() == null || prevEndRow() == null) {
       return false;
-
-    return prevExtent.getEndRow().equals(getPrevEndRow());
+    }
+    return prevExtent.endRow().equals(prevEndRow());
   }
 
   public boolean isMeta() {
-    return getTableId().equals(MetadataTable.ID) || isRootTablet();
+    return tableId().equals(MetadataTable.ID) || isRootTablet();
   }
 
   public boolean isRootTablet() {
-    return getTableId().equals(RootTable.ID);
+    return tableId().equals(RootTable.ID);
   }
 }
diff --git a/core/src/main/java/org/apache/accumulo/core/dataImpl/TabletIdImpl.java b/core/src/main/java/org/apache/accumulo/core/dataImpl/TabletIdImpl.java
index 06a4181..5ca015d 100644
--- a/core/src/main/java/org/apache/accumulo/core/dataImpl/TabletIdImpl.java
+++ b/core/src/main/java/org/apache/accumulo/core/dataImpl/TabletIdImpl.java
@@ -37,17 +37,17 @@ public class TabletIdImpl implements TabletId {
 
   @Override
   public Text getTableId() {
-    return new Text(ke.getTableId().canonical());
+    return new Text(ke.tableId().canonical());
   }
 
   @Override
   public Text getEndRow() {
-    return ke.getEndRow();
+    return ke.endRow();
   }
 
   @Override
   public Text getPrevEndRow() {
-    return ke.getPrevEndRow();
+    return ke.prevEndRow();
   }
 
   @Override
diff --git a/core/src/main/java/org/apache/accumulo/core/iteratorsImpl/system/MultiIterator.java b/core/src/main/java/org/apache/accumulo/core/iteratorsImpl/system/MultiIterator.java
index 1abb96e..02d530c 100644
--- a/core/src/main/java/org/apache/accumulo/core/iteratorsImpl/system/MultiIterator.java
+++ b/core/src/main/java/org/apache/accumulo/core/iteratorsImpl/system/MultiIterator.java
@@ -84,7 +84,7 @@ public class MultiIterator extends HeapIterator {
   }
 
   public MultiIterator(List<SortedKeyValueIterator<Key,Value>> iters2, KeyExtent extent) {
-    this(iters2, new Range(extent.getPrevEndRow(), false, extent.getEndRow(), true), false);
+    this(iters2, new Range(extent.prevEndRow(), false, extent.endRow(), true), false);
   }
 
   public MultiIterator(List<SortedKeyValueIterator<Key,Value>> readers, boolean init) {
diff --git a/core/src/main/java/org/apache/accumulo/core/metadata/MetadataLocationObtainer.java b/core/src/main/java/org/apache/accumulo/core/metadata/MetadataLocationObtainer.java
index 2051961..12c3b20 100644
--- a/core/src/main/java/org/apache/accumulo/core/metadata/MetadataLocationObtainer.java
+++ b/core/src/main/java/org/apache/accumulo/core/metadata/MetadataLocationObtainer.java
@@ -87,7 +87,7 @@ public class MetadataLocationObtainer implements TabletLocationObtainer {
 
       if (log.isTraceEnabled()) {
         log.trace("tid={} Looking up in {} row={} extent={} tserver={}",
-            Thread.currentThread().getId(), src.tablet_extent.getTableId(), TextUtil.truncate(row),
+            Thread.currentThread().getId(), src.tablet_extent.tableId(), TextUtil.truncate(row),
             src.tablet_extent, src.tablet_location);
         timer = new OpTimer().start();
       }
@@ -134,12 +134,12 @@ public class MetadataLocationObtainer implements TabletLocationObtainer {
 
     } catch (AccumuloServerException ase) {
       if (log.isTraceEnabled())
-        log.trace("{} lookup failed, {} server side exception", src.tablet_extent.getTableId(),
+        log.trace("{} lookup failed, {} server side exception", src.tablet_extent.tableId(),
             src.tablet_location);
       throw ase;
     } catch (AccumuloException e) {
       if (log.isTraceEnabled())
-        log.trace("{} lookup failed", src.tablet_extent.getTableId(), e);
+        log.trace("{} lookup failed", src.tablet_extent.tableId(), e);
       parent.invalidateCache(context, src.tablet_location);
     }
 
@@ -211,11 +211,8 @@ public class MetadataLocationObtainer implements TabletLocationObtainer {
   }
 
   public static TabletLocations getMetadataLocationEntries(SortedMap<Key,Value> entries) {
-    Key key;
-    Value val;
     Text location = null;
     Text session = null;
-    Value prevRow = null;
     KeyExtent ke;
 
     List<TabletLocation> results = new ArrayList<>();
@@ -228,11 +225,10 @@ public class MetadataLocationObtainer implements TabletLocationObtainer {
     Text colq = new Text();
 
     for (Entry<Key,Value> entry : entries.entrySet()) {
-      key = entry.getKey();
-      val = entry.getValue();
+      Key key = entry.getKey();
+      Value val = entry.getValue();
 
       if (key.compareRow(lastRowFromKey) != 0) {
-        prevRow = null;
         location = null;
         session = null;
         key.getRow(lastRowFromKey);
@@ -250,18 +246,12 @@ public class MetadataLocationObtainer implements TabletLocationObtainer {
         location = new Text(val.toString());
         session = new Text(colq);
       } else if (TabletColumnFamily.PREV_ROW_COLUMN.equals(colf, colq)) {
-        prevRow = new Value(val);
-      }
-
-      if (prevRow != null) {
-        ke = new KeyExtent(key.getRow(), prevRow);
+        ke = KeyExtent.fromMetaPrevRow(entry);
         if (location != null)
           results.add(new TabletLocation(ke, location.toString(), session.toString()));
         else
           locationless.add(ke);
-
         location = null;
-        prevRow = null;
       }
     }
 
diff --git a/core/src/main/java/org/apache/accumulo/core/metadata/RootTable.java b/core/src/main/java/org/apache/accumulo/core/metadata/RootTable.java
index 5f703f2..5b7b4b0 100644
--- a/core/src/main/java/org/apache/accumulo/core/metadata/RootTable.java
+++ b/core/src/main/java/org/apache/accumulo/core/metadata/RootTable.java
@@ -46,6 +46,6 @@ public class RootTable {
 
   public static final KeyExtent EXTENT = new KeyExtent(ID, null, null);
   public static final KeyExtent OLD_EXTENT =
-      new KeyExtent(MetadataTable.ID, TabletsSection.getRow(MetadataTable.ID, null), null);
+      new KeyExtent(MetadataTable.ID, TabletsSection.encodeRow(MetadataTable.ID, null), null);
 
 }
diff --git a/core/src/main/java/org/apache/accumulo/core/metadata/TableMetadataServicer.java b/core/src/main/java/org/apache/accumulo/core/metadata/TableMetadataServicer.java
index 628e8a2..47d3681 100644
--- a/core/src/main/java/org/apache/accumulo/core/metadata/TableMetadataServicer.java
+++ b/core/src/main/java/org/apache/accumulo/core/metadata/TableMetadataServicer.java
@@ -96,7 +96,7 @@ abstract class TableMetadataServicer extends MetadataServicer {
       colq = entry.getKey().getColumnQualifier(colq);
 
       if (TabletColumnFamily.PREV_ROW_COLUMN.equals(colf, colq)) {
-        currentKeyExtent = new KeyExtent(entry.getKey().getRow(), entry.getValue());
+        currentKeyExtent = KeyExtent.fromMetaPrevRow(entry);
         tablets.put(currentKeyExtent, location);
         currentKeyExtent = null;
         location = null;
@@ -117,28 +117,28 @@ abstract class TableMetadataServicer extends MetadataServicer {
       throw new AccumuloException(
           "No entries found in metadata table for table " + getServicedTableId());
 
-    if (tabletsKeys.first().getPrevEndRow() != null)
+    if (tabletsKeys.first().prevEndRow() != null)
       throw new AccumuloException("Problem with metadata table, first entry for table "
           + getServicedTableId() + "- " + tabletsKeys.first() + " - has non null prev end row");
 
-    if (tabletsKeys.last().getEndRow() != null)
+    if (tabletsKeys.last().endRow() != null)
       throw new AccumuloException("Problem with metadata table, last entry for table "
           + getServicedTableId() + "- " + tabletsKeys.first() + " - has non null end row");
 
     Iterator<KeyExtent> tabIter = tabletsKeys.iterator();
-    Text lastEndRow = tabIter.next().getEndRow();
+    Text lastEndRow = tabIter.next().endRow();
     while (tabIter.hasNext()) {
       KeyExtent tabke = tabIter.next();
 
-      if (tabke.getPrevEndRow() == null)
+      if (tabke.prevEndRow() == null)
         throw new AccumuloException(
             "Problem with metadata table, it has null prev end row in middle of table " + tabke);
 
-      if (!tabke.getPrevEndRow().equals(lastEndRow))
+      if (!tabke.prevEndRow().equals(lastEndRow))
         throw new AccumuloException("Problem with metadata table, it has a hole "
-            + tabke.getPrevEndRow() + " != " + lastEndRow);
+            + tabke.prevEndRow() + " != " + lastEndRow);
 
-      lastEndRow = tabke.getEndRow();
+      lastEndRow = tabke.endRow();
     }
 
     // end METADATA table sanity check
diff --git a/core/src/main/java/org/apache/accumulo/core/metadata/schema/LinkingIterator.java b/core/src/main/java/org/apache/accumulo/core/metadata/schema/LinkingIterator.java
index c745897..5cdbb00 100644
--- a/core/src/main/java/org/apache/accumulo/core/metadata/schema/LinkingIterator.java
+++ b/core/src/main/java/org/apache/accumulo/core/metadata/schema/LinkingIterator.java
@@ -69,7 +69,7 @@ public class LinkingIterator implements Iterator<TabletMetadata> {
     // Always expect the default tablet to exist for a table. The following checks for the case when
     // the default tablet was not seen when it should have been seen.
     if (!hasNext && prevTablet != null && prevTablet.getEndRow() != null) {
-      Text defaultTabletRow = TabletsSection.getRow(prevTablet.getTableId(), null);
+      Text defaultTabletRow = TabletsSection.encodeRow(prevTablet.getTableId(), null);
       if (range.contains(new Key(defaultTabletRow))) {
         throw new IllegalStateException(
             "Scan range incudled default tablet, but did not see default tablet.  Last tablet seen : "
@@ -120,7 +120,7 @@ public class LinkingIterator implements Iterator<TabletMetadata> {
       source = iteratorFactory.apply(range);
     } else {
       // get the metadata table row for the previous tablet
-      Text prevMetaRow = TabletsSection.getRow(prevTablet.getTableId(), prevTablet.getEndRow());
+      Text prevMetaRow = TabletsSection.encodeRow(prevTablet.getTableId(), prevTablet.getEndRow());
 
       // ensure the previous tablet still exists in the metadata table
       if (Iterators.size(iteratorFactory.apply(new Range(prevMetaRow))) == 0) {
@@ -153,8 +153,8 @@ public class LinkingIterator implements Iterator<TabletMetadata> {
 
           KeyExtent extent = tmp.getExtent();
 
-          if (extent.getPrevEndRow() != null) {
-            prevMetaRow = TabletsSection.getRow(extent.getTableId(), extent.getPrevEndRow());
+          if (extent.prevEndRow() != null) {
+            prevMetaRow = TabletsSection.encodeRow(extent.tableId(), extent.prevEndRow());
           }
 
           // If the first tablet seen has a prev endrow within the range it means a preceding tablet
diff --git a/core/src/main/java/org/apache/accumulo/core/metadata/schema/MetadataSchema.java b/core/src/main/java/org/apache/accumulo/core/metadata/schema/MetadataSchema.java
index 61ecbb6..6a13a78 100644
--- a/core/src/main/java/org/apache/accumulo/core/metadata/schema/MetadataSchema.java
+++ b/core/src/main/java/org/apache/accumulo/core/metadata/schema/MetadataSchema.java
@@ -19,17 +19,21 @@
 package org.apache.accumulo.core.metadata.schema;
 
 import static com.google.common.base.Preconditions.checkArgument;
+import static java.nio.charset.StandardCharsets.UTF_8;
 import static java.util.Objects.requireNonNull;
 
 import org.apache.accumulo.core.client.admin.TimeType;
 import org.apache.accumulo.core.data.ArrayByteSequence;
 import org.apache.accumulo.core.data.Key;
+import org.apache.accumulo.core.data.Mutation;
 import org.apache.accumulo.core.data.PartialKey;
 import org.apache.accumulo.core.data.Range;
 import org.apache.accumulo.core.data.TableId;
 import org.apache.accumulo.core.data.Value;
+import org.apache.accumulo.core.dataImpl.KeyExtent;
 import org.apache.accumulo.core.schema.Section;
 import org.apache.accumulo.core.util.ColumnFQ;
+import org.apache.accumulo.core.util.Pair;
 import org.apache.accumulo.fate.FateTxId;
 import org.apache.hadoop.io.Text;
 
@@ -57,7 +61,7 @@ public class MetadataSchema {
           new Key(tableId.canonical() + '<').followingKey(PartialKey.ROW), false);
     }
 
-    public static Text getRow(TableId tableId, Text endRow) {
+    public static Text encodeRow(TableId tableId, Text endRow) {
       Text entry = new Text(tableId.canonical());
 
       if (endRow == null) {
@@ -73,6 +77,43 @@ public class MetadataSchema {
     }
 
     /**
+     * Decodes a metadata row into a pair of table ID and end row.
+     */
+    public static Pair<TableId,Text> decodeRow(Text metadataRow) {
+      int semiPos = -1;
+      int ltPos = -1;
+
+      for (int i = 0; i < metadataRow.getLength(); i++) {
+        if (metadataRow.getBytes()[i] == ';' && semiPos < 0) {
+          // want the position of the first semicolon
+          semiPos = i;
+        }
+        if (metadataRow.getBytes()[i] == '<') {
+          ltPos = i;
+        }
+      }
+
+      if (semiPos < 0 && ltPos < 0) {
+        throw new IllegalArgumentException("Metadata row does not contain ; or <  " + metadataRow);
+      }
+
+      if (semiPos < 0) {
+        // default tablet ending in '<'
+        if (ltPos != metadataRow.getLength() - 1) {
+          throw new IllegalArgumentException("< must come at end of Metadata row  " + metadataRow);
+        }
+        TableId tableId = TableId.of(new String(metadataRow.getBytes(), 0, ltPos, UTF_8));
+        return new Pair<>(tableId, null);
+      } else {
+        // other tablets containing ';'
+        TableId tableId = TableId.of(new String(metadataRow.getBytes(), 0, semiPos, UTF_8));
+        Text endRow = new Text();
+        endRow.set(metadataRow.getBytes(), semiPos + 1, metadataRow.getLength() - (semiPos + 1));
+        return new Pair<>(tableId, endRow);
+      }
+    }
+
+    /**
      * Column family for storing the tablet information needed by clients
      */
     public static class TabletColumnFamily {
@@ -89,6 +130,28 @@ public class MetadataSchema {
        */
       public static final String PREV_ROW_QUAL = "~pr";
       public static final ColumnFQ PREV_ROW_COLUMN = new ColumnFQ(NAME, new Text(PREV_ROW_QUAL));
+
+      public static Value encodePrevEndRow(Text per) {
+        if (per == null) {
+          return new Value(new byte[] {0});
+        }
+        byte[] b = new byte[per.getLength() + 1];
+        b[0] = 1;
+        System.arraycopy(per.getBytes(), 0, b, 1, per.getLength());
+        return new Value(b);
+      }
+
+      public static Text decodePrevEndRow(Value ibw) {
+        Text per = null;
+
+        if (ibw.get()[0] != 0) {
+          per = new Text();
+          per.set(ibw.get(), 1, ibw.get().length - 1);
+        }
+
+        return per;
+      }
+
       /**
        * A temporary field in case a split fails and we need to roll back
        */
@@ -101,6 +164,15 @@ public class MetadataSchema {
       public static final String SPLIT_RATIO_QUAL = "splitRatio";
       public static final ColumnFQ SPLIT_RATIO_COLUMN =
           new ColumnFQ(NAME, new Text(SPLIT_RATIO_QUAL));
+
+      /**
+       * Creates a mutation that encodes a KeyExtent as a prevRow entry.
+       */
+      public static Mutation createPrevRowMutation(KeyExtent ke) {
+        Mutation m = new Mutation(ke.toMetaRow());
+        PREV_ROW_COLUMN.put(m, encodePrevEndRow(ke.prevEndRow()));
+        return m;
+      }
     }
 
     /**
diff --git a/core/src/main/java/org/apache/accumulo/core/metadata/schema/RootTabletMetadata.java b/core/src/main/java/org/apache/accumulo/core/metadata/schema/RootTabletMetadata.java
index 7d5cf40..81d204e 100644
--- a/core/src/main/java/org/apache/accumulo/core/metadata/schema/RootTabletMetadata.java
+++ b/core/src/main/java/org/apache/accumulo/core/metadata/schema/RootTabletMetadata.java
@@ -39,6 +39,7 @@ import org.apache.accumulo.core.metadata.schema.MetadataSchema.TabletsSection.Cu
 import org.apache.accumulo.core.metadata.schema.MetadataSchema.TabletsSection.DataFileColumnFamily;
 import org.apache.accumulo.core.metadata.schema.MetadataSchema.TabletsSection.FutureLocationColumnFamily;
 import org.apache.accumulo.core.metadata.schema.MetadataSchema.TabletsSection.ServerColumnFamily;
+import org.apache.accumulo.core.metadata.schema.MetadataSchema.TabletsSection.TabletColumnFamily;
 import org.apache.accumulo.core.metadata.schema.TabletMetadata.ColumnType;
 import org.apache.hadoop.io.Text;
 
@@ -73,7 +74,7 @@ public class RootTabletMetadata {
    * Apply a metadata table mutation to update internal json.
    */
   public void update(Mutation m) {
-    Preconditions.checkArgument(new Text(m.getRow()).equals(RootTable.EXTENT.getMetadataEntry()));
+    Preconditions.checkArgument(new Text(m.getRow()).equals(RootTable.EXTENT.toMetaRow()));
 
     m.getUpdates().forEach(cup -> {
       Preconditions.checkArgument(!cup.hasTimestamp());
@@ -150,7 +151,7 @@ public class RootTabletMetadata {
 
     Preconditions.checkArgument(gd.version == 1);
 
-    String row = RootTable.EXTENT.getMetadataEntry().toString();
+    String row = RootTable.EXTENT.toMetaRow().toString();
 
     TreeMap<Key,Value> entries = new TreeMap<>();
 
@@ -182,7 +183,7 @@ public class RootTabletMetadata {
    */
   public static byte[] getInitialJson(String dirName, String file) {
     ServerColumnFamily.validateDirCol(dirName);
-    Mutation mutation = RootTable.EXTENT.getPrevRowUpdateMutation();
+    Mutation mutation = TabletColumnFamily.createPrevRowMutation(RootTable.EXTENT);
     ServerColumnFamily.DIRECTORY_COLUMN.put(mutation, new Value(dirName));
 
     mutation.put(DataFileColumnFamily.STR_NAME, file, new DataFileValue(0, 0).encodeAsValue());
diff --git a/core/src/main/java/org/apache/accumulo/core/metadata/schema/TabletMetadata.java b/core/src/main/java/org/apache/accumulo/core/metadata/schema/TabletMetadata.java
index f552be7..c854192 100644
--- a/core/src/main/java/org/apache/accumulo/core/metadata/schema/TabletMetadata.java
+++ b/core/src/main/java/org/apache/accumulo/core/metadata/schema/TabletMetadata.java
@@ -301,9 +301,9 @@ public class TabletMetadata {
 
       if (row == null) {
         row = key.getRowData();
-        KeyExtent ke = new KeyExtent(key.getRow(), (Text) null);
-        te.endRow = ke.getEndRow();
-        te.tableId = ke.getTableId();
+        KeyExtent ke = KeyExtent.fromMetaRow(key.getRow());
+        te.endRow = ke.endRow();
+        te.tableId = ke.tableId();
       } else if (!row.equals(key.getRowData())) {
         throw new IllegalArgumentException(
             "Input contains more than one row : " + row + " " + key.getRowData());
@@ -313,11 +313,11 @@ public class TabletMetadata {
         case TabletColumnFamily.STR_NAME:
           switch (qual) {
             case PREV_ROW_QUAL:
-              te.prevEndRow = KeyExtent.decodePrevEndRow(kv.getValue());
+              te.prevEndRow = TabletColumnFamily.decodePrevEndRow(kv.getValue());
               te.sawPrevEndRow = true;
               break;
             case OLD_PREV_ROW_QUAL:
-              te.oldPrevEndRow = KeyExtent.decodePrevEndRow(kv.getValue());
+              te.oldPrevEndRow = TabletColumnFamily.decodePrevEndRow(kv.getValue());
               te.sawOldPrevEndRow = true;
               break;
             case SPLIT_RATIO_QUAL:
diff --git a/core/src/main/java/org/apache/accumulo/core/metadata/schema/TabletsMetadata.java b/core/src/main/java/org/apache/accumulo/core/metadata/schema/TabletsMetadata.java
index f8ef8e5..57ecbb7 100644
--- a/core/src/main/java/org/apache/accumulo/core/metadata/schema/TabletsMetadata.java
+++ b/core/src/main/java/org/apache/accumulo/core/metadata/schema/TabletsMetadata.java
@@ -211,8 +211,8 @@ public class TabletsMetadata implements Iterable<TabletMetadata>, AutoCloseable
 
     @Override
     public Options forTablet(KeyExtent extent) {
-      forTable(extent.getTableId());
-      this.range = new Range(extent.getMetadataEntry());
+      forTable(extent.tableId());
+      this.range = new Range(extent.toMetaRow());
       return this;
     }
 
@@ -224,7 +224,7 @@ public class TabletsMetadata implements Iterable<TabletMetadata>, AutoCloseable
 
     @Override
     public Options overlapping(Text startRow, Text endRow) {
-      this.range = new KeyExtent(tableId, null, startRow).toMetadataRange();
+      this.range = new KeyExtent(tableId, null, startRow).toMetaRange();
       this.endRow = endRow;
       return this;
     }
diff --git a/core/src/main/java/org/apache/accumulo/core/summary/Gatherer.java b/core/src/main/java/org/apache/accumulo/core/summary/Gatherer.java
index f756a97..882d94c 100644
--- a/core/src/main/java/org/apache/accumulo/core/summary/Gatherer.java
+++ b/core/src/main/java/org/apache/accumulo/core/summary/Gatherer.java
@@ -632,8 +632,8 @@ public class Gatherer {
     private Text endRow;
 
     public RowRange(KeyExtent ke) {
-      this.startRow = ke.getPrevEndRow();
-      this.endRow = ke.getEndRow();
+      this.startRow = ke.prevEndRow();
+      this.endRow = ke.endRow();
     }
 
     public RowRange(TRowRange trr) {
diff --git a/core/src/main/java/org/apache/accumulo/core/tabletserver/log/LogEntry.java b/core/src/main/java/org/apache/accumulo/core/tabletserver/log/LogEntry.java
index bbfe8d2..6d5aee7 100644
--- a/core/src/main/java/org/apache/accumulo/core/tabletserver/log/LogEntry.java
+++ b/core/src/main/java/org/apache/accumulo/core/tabletserver/log/LogEntry.java
@@ -51,7 +51,7 @@ public class LogEntry {
 
   @Override
   public String toString() {
-    return extent + " " + filename;
+    return extent.toMetaRow() + " " + filename;
   }
 
   public String getName() {
@@ -60,7 +60,7 @@ public class LogEntry {
 
   public byte[] toBytes() throws IOException {
     DataOutputBuffer out = new DataOutputBuffer();
-    extent.write(out);
+    extent.writeTo(out);
     out.writeLong(timestamp);
     out.writeUTF(server);
     out.writeUTF(filename);
@@ -70,22 +70,19 @@ public class LogEntry {
   public static LogEntry fromBytes(byte[] bytes) throws IOException {
     DataInputBuffer inp = new DataInputBuffer();
     inp.reset(bytes, bytes.length);
-    KeyExtent extent = new KeyExtent();
-    extent.readFields(inp);
+    KeyExtent extent = KeyExtent.readFrom(inp);
     long timestamp = inp.readLong();
     String server = inp.readUTF();
     String filename = inp.readUTF();
     return new LogEntry(extent, timestamp, server, filename);
   }
 
-  private static final Text EMPTY_TEXT = new Text();
-
   public static LogEntry fromKeyValue(Key key, String value) {
     String qualifier = key.getColumnQualifierData().toString();
     if (qualifier.indexOf('/') < 1) {
       throw new IllegalArgumentException("Bad key for log entry: " + key);
     }
-    KeyExtent extent = new KeyExtent(key.getRow(), EMPTY_TEXT);
+    KeyExtent extent = KeyExtent.fromMetaRow(key.getRow());
     String[] parts = qualifier.split("/", 2);
     String server = parts[0];
     // handle old-style log entries that specify log sets
@@ -100,7 +97,7 @@ public class LogEntry {
   }
 
   public Text getRow() {
-    return extent.getMetadataEntry();
+    return extent.toMetaRow();
   }
 
   public Text getColumnFamily() {
diff --git a/core/src/main/java/org/apache/accumulo/core/util/Merge.java b/core/src/main/java/org/apache/accumulo/core/util/Merge.java
index 70413ce..eef0bcd 100644
--- a/core/src/main/java/org/apache/accumulo/core/util/Merge.java
+++ b/core/src/main/java/org/apache/accumulo/core/util/Merge.java
@@ -216,8 +216,8 @@ public class Merge {
   protected void merge(AccumuloClient client, String table, List<Size> sizes, int numToMerge)
       throws MergeException {
     try {
-      Text start = sizes.get(0).extent.getPrevEndRow();
-      Text end = sizes.get(numToMerge - 1).extent.getEndRow();
+      Text start = sizes.get(0).extent.prevEndRow();
+      Text end = sizes.get(numToMerge - 1).extent.endRow();
       message("Merging %d tablets from (%s to %s]", numToMerge, start == null ? "-inf" : start,
           end == null ? "+inf" : end);
       client.tableOperations().merge(table, start, end);
@@ -236,7 +236,7 @@ public class Merge {
       ClientContext context = (ClientContext) client;
       tableId = Tables.getTableId(context, tablename);
       tablets = TabletsMetadata.builder().scanMetadataTable()
-          .overRange(new KeyExtent(tableId, end, start).toMetadataRange()).fetch(FILES, PREV_ROW)
+          .overRange(new KeyExtent(tableId, end, start).toMetaRange()).fetch(FILES, PREV_ROW)
           .build(context);
     } catch (Exception e) {
       throw new MergeException(e);
diff --git a/core/src/test/java/org/apache/accumulo/core/clientImpl/TabletLocatorImplTest.java b/core/src/test/java/org/apache/accumulo/core/clientImpl/TabletLocatorImplTest.java
index f4f85f4..74e9786 100644
--- a/core/src/test/java/org/apache/accumulo/core/clientImpl/TabletLocatorImplTest.java
+++ b/core/src/test/java/org/apache/accumulo/core/clientImpl/TabletLocatorImplTest.java
@@ -61,7 +61,7 @@ import org.junit.Test;
 public class TabletLocatorImplTest {
 
   private static final KeyExtent RTE = RootTable.EXTENT;
-  private static final KeyExtent MTE = new KeyExtent(MetadataTable.ID, null, RTE.getEndRow());
+  private static final KeyExtent MTE = new KeyExtent(MetadataTable.ID, null, RTE.endRow());
 
   static KeyExtent nke(String t, String er, String per) {
     return new KeyExtent(TableId.of(t), er == null ? null : new Text(er),
@@ -126,10 +126,10 @@ public class TabletLocatorImplTest {
     TreeMap<Text,TabletLocation> mc = new TreeMap<>(TabletLocatorImpl.END_ROW_COMPARATOR);
 
     for (Entry<KeyExtent,TabletLocation> entry : mcke.entrySet()) {
-      if (entry.getKey().getEndRow() == null)
+      if (entry.getKey().endRow() == null)
         mc.put(TabletLocatorImpl.MAX_TEXT, entry.getValue());
       else
-        mc.put(entry.getKey().getEndRow(), entry.getValue());
+        mc.put(entry.getKey().endRow(), entry.getValue());
     }
 
     return mc;
@@ -539,7 +539,7 @@ public class TabletLocatorImplTest {
       return;
     }
 
-    Text mr = ke.getMetadataEntry();
+    Text mr = ke.toMetaRow();
     Key lk = new Key(mr, CurrentLocationColumnFamily.NAME, new Text(instance));
     tabletData.remove(lk);
 
@@ -552,8 +552,8 @@ public class TabletLocatorImplTest {
 
     SortedMap<Key,Value> tabletData = tablets.computeIfAbsent(tablet, k -> new TreeMap<>());
 
-    Text mr = ke.getMetadataEntry();
-    Value per = KeyExtent.encodePrevEndRow(ke.getPrevEndRow());
+    Text mr = ke.toMetaRow();
+    Value per = TabletColumnFamily.encodePrevEndRow(ke.prevEndRow());
 
     if (location != null) {
       if (instance == null)
@@ -689,8 +689,8 @@ public class TabletLocatorImplTest {
     locateTabletTest(tab1TabletCache, "r", tab1e22, "tserver3");
 
     // simulate the metadata table splitting
-    KeyExtent mte1 = new KeyExtent(MetadataTable.ID, tab1e21.getMetadataEntry(), RTE.getEndRow());
-    KeyExtent mte2 = new KeyExtent(MetadataTable.ID, null, tab1e21.getMetadataEntry());
+    KeyExtent mte1 = new KeyExtent(MetadataTable.ID, tab1e21.toMetaRow(), RTE.endRow());
+    KeyExtent mte2 = new KeyExtent(MetadataTable.ID, null, tab1e21.toMetaRow());
 
     setLocation(tservers, "tserver4", RTE, mte1, "tserver5");
     setLocation(tservers, "tserver4", RTE, mte2, "tserver6");
@@ -728,9 +728,8 @@ public class TabletLocatorImplTest {
     locateTabletTest(tab1TabletCache, "r", tab1e22, "tserver9");
 
     // simulate a hole in the metadata, caused by a partial split
-    KeyExtent mte11 = new KeyExtent(MetadataTable.ID, tab1e1.getMetadataEntry(), RTE.getEndRow());
-    KeyExtent mte12 =
-        new KeyExtent(MetadataTable.ID, tab1e21.getMetadataEntry(), tab1e1.getMetadataEntry());
+    KeyExtent mte11 = new KeyExtent(MetadataTable.ID, tab1e1.toMetaRow(), RTE.endRow());
+    KeyExtent mte12 = new KeyExtent(MetadataTable.ID, tab1e21.toMetaRow(), tab1e1.toMetaRow());
     deleteServer(tservers, "tserver10");
     setLocation(tservers, "tserver4", RTE, mte12, "tserver10");
     setLocation(tservers, "tserver10", mte12, tab1e21, "tserver12");
@@ -1181,7 +1180,7 @@ public class TabletLocatorImplTest {
   @Test
   public void testBug1() throws Exception {
     // a bug that occurred while running continuous ingest
-    KeyExtent mte1 = new KeyExtent(MetadataTable.ID, new Text("0;0bc"), RTE.getEndRow());
+    KeyExtent mte1 = new KeyExtent(MetadataTable.ID, new Text("0;0bc"), RTE.endRow());
     KeyExtent mte2 = new KeyExtent(MetadataTable.ID, null, new Text("0;0bc"));
 
     TServers tservers = new TServers();
@@ -1210,7 +1209,7 @@ public class TabletLocatorImplTest {
   @Test
   public void testBug2() throws Exception {
     // a bug that occurred while running a functional test
-    KeyExtent mte1 = new KeyExtent(MetadataTable.ID, new Text("~"), RTE.getEndRow());
+    KeyExtent mte1 = new KeyExtent(MetadataTable.ID, new Text("~"), RTE.endRow());
     KeyExtent mte2 = new KeyExtent(MetadataTable.ID, null, new Text("~"));
 
     TServers tservers = new TServers();
@@ -1238,7 +1237,7 @@ public class TabletLocatorImplTest {
   // being merged away, caused locating tablets to fail
   @Test
   public void testBug3() throws Exception {
-    KeyExtent mte1 = new KeyExtent(MetadataTable.ID, new Text("1;c"), RTE.getEndRow());
+    KeyExtent mte1 = new KeyExtent(MetadataTable.ID, new Text("1;c"), RTE.endRow());
     KeyExtent mte2 = new KeyExtent(MetadataTable.ID, new Text("1;f"), new Text("1;c"));
     KeyExtent mte3 = new KeyExtent(MetadataTable.ID, new Text("1;j"), new Text("1;f"));
     KeyExtent mte4 = new KeyExtent(MetadataTable.ID, new Text("1;r"), new Text("1;j"));
diff --git a/core/src/test/java/org/apache/accumulo/core/data/KeyExtentTest.java b/core/src/test/java/org/apache/accumulo/core/data/KeyExtentTest.java
index 9a23b97..c798c84 100644
--- a/core/src/test/java/org/apache/accumulo/core/data/KeyExtentTest.java
+++ b/core/src/test/java/org/apache/accumulo/core/data/KeyExtentTest.java
@@ -55,123 +55,27 @@ public class KeyExtentTest {
   public void testDecodingMetadataRow() {
     Text flattenedExtent = new Text("foo;bar");
 
-    ke = new KeyExtent(flattenedExtent, (Text) null);
+    ke = KeyExtent.fromMetaRow(flattenedExtent);
 
-    assertEquals(new Text("bar"), ke.getEndRow());
-    assertEquals("foo", ke.getTableId().canonical());
-    assertNull(ke.getPrevEndRow());
+    assertEquals(new Text("bar"), ke.endRow());
+    assertEquals("foo", ke.tableId().canonical());
+    assertNull(ke.prevEndRow());
 
     flattenedExtent = new Text("foo<");
 
-    ke = new KeyExtent(flattenedExtent, (Text) null);
+    ke = KeyExtent.fromMetaRow(flattenedExtent);
 
-    assertNull(ke.getEndRow());
-    assertEquals("foo", ke.getTableId().canonical());
-    assertNull(ke.getPrevEndRow());
+    assertNull(ke.endRow());
+    assertEquals("foo", ke.tableId().canonical());
+    assertNull(ke.prevEndRow());
 
     flattenedExtent = new Text("foo;bar;");
 
-    ke = new KeyExtent(flattenedExtent, (Text) null);
+    ke = KeyExtent.fromMetaRow(flattenedExtent);
 
-    assertEquals(new Text("bar;"), ke.getEndRow());
-    assertEquals("foo", ke.getTableId().canonical());
-    assertNull(ke.getPrevEndRow());
-
-  }
-
-  @Test
-  public void testFindContainingExtents() {
-    assertNull(KeyExtent.findContainingExtent(nke("t", null, null), set0));
-    assertNull(KeyExtent.findContainingExtent(nke("t", "1", "0"), set0));
-    assertNull(KeyExtent.findContainingExtent(nke("t", "1", null), set0));
-    assertNull(KeyExtent.findContainingExtent(nke("t", null, "0"), set0));
-
-    TreeSet<KeyExtent> set1 = new TreeSet<>();
-
-    set1.add(nke("t", null, null));
-
-    assertEquals(nke("t", null, null), KeyExtent.findContainingExtent(nke("t", null, null), set1));
-    assertEquals(nke("t", null, null), KeyExtent.findContainingExtent(nke("t", "1", "0"), set1));
-    assertEquals(nke("t", null, null), KeyExtent.findContainingExtent(nke("t", "1", null), set1));
-    assertEquals(nke("t", null, null), KeyExtent.findContainingExtent(nke("t", null, "0"), set1));
-
-    TreeSet<KeyExtent> set2 = new TreeSet<>();
-
-    set2.add(nke("t", "g", null));
-    set2.add(nke("t", null, "g"));
-
-    assertNull(KeyExtent.findContainingExtent(nke("t", null, null), set2));
-    assertEquals(nke("t", "g", null), KeyExtent.findContainingExtent(nke("t", "c", "a"), set2));
-    assertEquals(nke("t", "g", null), KeyExtent.findContainingExtent(nke("t", "c", null), set2));
-
-    assertEquals(nke("t", "g", null), KeyExtent.findContainingExtent(nke("t", "g", "a"), set2));
-    assertEquals(nke("t", "g", null), KeyExtent.findContainingExtent(nke("t", "g", null), set2));
-
-    assertNull(KeyExtent.findContainingExtent(nke("t", "h", "a"), set2));
-    assertNull(KeyExtent.findContainingExtent(nke("t", "h", null), set2));
-
-    assertNull(KeyExtent.findContainingExtent(nke("t", "z", "f"), set2));
-    assertNull(KeyExtent.findContainingExtent(nke("t", null, "f"), set2));
-
-    assertEquals(nke("t", null, "g"), KeyExtent.findContainingExtent(nke("t", "z", "g"), set2));
-    assertEquals(nke("t", null, "g"), KeyExtent.findContainingExtent(nke("t", null, "g"), set2));
-
-    assertEquals(nke("t", null, "g"), KeyExtent.findContainingExtent(nke("t", "z", "h"), set2));
-    assertEquals(nke("t", null, "g"), KeyExtent.findContainingExtent(nke("t", null, "h"), set2));
-
-    TreeSet<KeyExtent> set3 = new TreeSet<>();
-
-    set3.add(nke("t", "g", null));
-    set3.add(nke("t", "s", "g"));
-    set3.add(nke("t", null, "s"));
-
-    assertNull(KeyExtent.findContainingExtent(nke("t", null, null), set3));
-
-    assertEquals(nke("t", "g", null), KeyExtent.findContainingExtent(nke("t", "g", null), set3));
-    assertEquals(nke("t", "s", "g"), KeyExtent.findContainingExtent(nke("t", "s", "g"), set3));
-    assertEquals(nke("t", null, "s"), KeyExtent.findContainingExtent(nke("t", null, "s"), set3));
-
-    assertNull(KeyExtent.findContainingExtent(nke("t", "t", "g"), set3));
-    assertNull(KeyExtent.findContainingExtent(nke("t", "t", "f"), set3));
-    assertNull(KeyExtent.findContainingExtent(nke("t", "s", "f"), set3));
-
-    assertEquals(nke("t", "s", "g"), KeyExtent.findContainingExtent(nke("t", "r", "h"), set3));
-    assertEquals(nke("t", "s", "g"), KeyExtent.findContainingExtent(nke("t", "s", "h"), set3));
-    assertEquals(nke("t", "s", "g"), KeyExtent.findContainingExtent(nke("t", "r", "g"), set3));
-
-    assertEquals(nke("t", null, "s"), KeyExtent.findContainingExtent(nke("t", null, "t"), set3));
-    assertNull(KeyExtent.findContainingExtent(nke("t", null, "r"), set3));
-
-    assertEquals(nke("t", "g", null), KeyExtent.findContainingExtent(nke("t", "f", null), set3));
-    assertNull(KeyExtent.findContainingExtent(nke("t", "h", null), set3));
-
-    TreeSet<KeyExtent> set4 = new TreeSet<>();
-
-    set4.add(nke("t1", "d", null));
-    set4.add(nke("t1", "q", "d"));
-    set4.add(nke("t1", null, "q"));
-    set4.add(nke("t2", "g", null));
-    set4.add(nke("t2", "s", "g"));
-    set4.add(nke("t2", null, "s"));
-
-    assertNull(KeyExtent.findContainingExtent(nke("t", null, null), set4));
-    assertNull(KeyExtent.findContainingExtent(nke("z", null, null), set4));
-    assertNull(KeyExtent.findContainingExtent(nke("t11", null, null), set4));
-    assertNull(KeyExtent.findContainingExtent(nke("t1", null, null), set4));
-    assertNull(KeyExtent.findContainingExtent(nke("t2", null, null), set4));
-
-    assertNull(KeyExtent.findContainingExtent(nke("t", "g", null), set4));
-    assertNull(KeyExtent.findContainingExtent(nke("z", "g", null), set4));
-    assertNull(KeyExtent.findContainingExtent(nke("t11", "g", null), set4));
-    assertNull(KeyExtent.findContainingExtent(nke("t1", "g", null), set4));
-
-    assertEquals(nke("t2", "g", null), KeyExtent.findContainingExtent(nke("t2", "g", null), set4));
-    assertEquals(nke("t2", "s", "g"), KeyExtent.findContainingExtent(nke("t2", "s", "g"), set4));
-    assertEquals(nke("t2", null, "s"), KeyExtent.findContainingExtent(nke("t2", null, "s"), set4));
-
-    assertEquals(nke("t1", "d", null), KeyExtent.findContainingExtent(nke("t1", "d", null), set4));
-    assertEquals(nke("t1", "q", "d"), KeyExtent.findContainingExtent(nke("t1", "q", "d"), set4));
-    assertEquals(nke("t1", null, "q"), KeyExtent.findContainingExtent(nke("t1", null, "q"), set4));
+    assertEquals(new Text("bar;"), ke.endRow());
+    assertEquals("foo", ke.tableId().canonical());
+    assertNull(ke.prevEndRow());
 
   }
 
@@ -277,22 +181,12 @@ public class KeyExtentTest {
   }
 
   private KeyExtent writeAndReadFields(KeyExtent in) throws IOException {
-    KeyExtent out = new KeyExtent();
 
     ByteArrayOutputStream baos = new ByteArrayOutputStream();
-    in.write(new DataOutputStream(baos));
+    in.writeTo(new DataOutputStream(baos));
 
     ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
-    out.readFields(new DataInputStream(bais));
-
-    return out;
+    return KeyExtent.readFrom(new DataInputStream(bais));
   }
 
-  @Test
-  public void testDecodeEncode() {
-    assertNull(KeyExtent.decodePrevEndRow(KeyExtent.encodePrevEndRow(null)));
-
-    Text x = new Text();
-    assertEquals(x, KeyExtent.decodePrevEndRow(KeyExtent.encodePrevEndRow(x)));
-  }
 }
diff --git a/core/src/test/java/org/apache/accumulo/core/data/RangeTest.java b/core/src/test/java/org/apache/accumulo/core/data/RangeTest.java
index b6eb77f..3e6ce82 100644
--- a/core/src/test/java/org/apache/accumulo/core/data/RangeTest.java
+++ b/core/src/test/java/org/apache/accumulo/core/data/RangeTest.java
@@ -229,39 +229,37 @@ public class RangeTest {
   @Test
   public void testMergeOverlapping22() {
 
-    Range ke1 = new KeyExtent(TableId.of("tab1"), new Text("Bank"), null).toMetadataRange();
+    Range ke1 = new KeyExtent(TableId.of("tab1"), new Text("Bank"), null).toMetaRange();
     Range ke2 =
-        new KeyExtent(TableId.of("tab1"), new Text("Fails"), new Text("Bank")).toMetadataRange();
-    Range ke3 =
-        new KeyExtent(TableId.of("tab1"), new Text("Sam"), new Text("Fails")).toMetadataRange();
-    Range ke4 =
-        new KeyExtent(TableId.of("tab1"), new Text("bails"), new Text("Sam")).toMetadataRange();
-    Range ke5 = new KeyExtent(TableId.of("tab1"), null, new Text("bails")).toMetadataRange();
+        new KeyExtent(TableId.of("tab1"), new Text("Fails"), new Text("Bank")).toMetaRange();
+    Range ke3 = new KeyExtent(TableId.of("tab1"), new Text("Sam"), new Text("Fails")).toMetaRange();
+    Range ke4 = new KeyExtent(TableId.of("tab1"), new Text("bails"), new Text("Sam")).toMetaRange();
+    Range ke5 = new KeyExtent(TableId.of("tab1"), null, new Text("bails")).toMetaRange();
 
     List<Range> rl = newRangeList(ke1, ke2, ke3, ke4, ke5);
     List<Range> expected =
-        newRangeList(new KeyExtent(TableId.of("tab1"), null, null).toMetadataRange());
+        newRangeList(new KeyExtent(TableId.of("tab1"), null, null).toMetaRange());
     check(Range.mergeOverlapping(rl), expected);
 
     rl = newRangeList(ke1, ke2, ke4, ke5);
     expected =
-        newRangeList(new KeyExtent(TableId.of("tab1"), new Text("Fails"), null).toMetadataRange(),
-            new KeyExtent(TableId.of("tab1"), null, new Text("Sam")).toMetadataRange());
+        newRangeList(new KeyExtent(TableId.of("tab1"), new Text("Fails"), null).toMetaRange(),
+            new KeyExtent(TableId.of("tab1"), null, new Text("Sam")).toMetaRange());
     check(Range.mergeOverlapping(rl), expected);
 
     rl = newRangeList(ke2, ke3, ke4, ke5);
     expected =
-        newRangeList(new KeyExtent(TableId.of("tab1"), null, new Text("Bank")).toMetadataRange());
+        newRangeList(new KeyExtent(TableId.of("tab1"), null, new Text("Bank")).toMetaRange());
     check(Range.mergeOverlapping(rl), expected);
 
     rl = newRangeList(ke1, ke2, ke3, ke4);
     expected =
-        newRangeList(new KeyExtent(TableId.of("tab1"), new Text("bails"), null).toMetadataRange());
+        newRangeList(new KeyExtent(TableId.of("tab1"), new Text("bails"), null).toMetaRange());
     check(Range.mergeOverlapping(rl), expected);
 
     rl = newRangeList(ke2, ke3, ke4);
     expected = newRangeList(
-        new KeyExtent(TableId.of("tab1"), new Text("bails"), new Text("Bank")).toMetadataRange());
+        new KeyExtent(TableId.of("tab1"), new Text("bails"), new Text("Bank")).toMetaRange());
 
     check(Range.mergeOverlapping(rl), expected);
   }
diff --git a/core/src/test/java/org/apache/accumulo/core/file/rfile/RFileTest.java b/core/src/test/java/org/apache/accumulo/core/file/rfile/RFileTest.java
index 0c9ba01..617ca93 100644
--- a/core/src/test/java/org/apache/accumulo/core/file/rfile/RFileTest.java
+++ b/core/src/test/java/org/apache/accumulo/core/file/rfile/RFileTest.java
@@ -64,7 +64,6 @@ import org.apache.accumulo.core.data.Key;
 import org.apache.accumulo.core.data.PartialKey;
 import org.apache.accumulo.core.data.Range;
 import org.apache.accumulo.core.data.Value;
-import org.apache.accumulo.core.dataImpl.KeyExtent;
 import org.apache.accumulo.core.file.FileSKVIterator;
 import org.apache.accumulo.core.file.blockfile.cache.impl.BlockCacheConfiguration;
 import org.apache.accumulo.core.file.blockfile.cache.impl.BlockCacheManagerFactory;
@@ -2337,7 +2336,7 @@ public class RFileTest {
     // mfw.startDefaultLocalityGroup();
 
     Text tableExtent = new Text(
-        TabletsSection.getRow(MetadataTable.ID, TabletsSection.getRange().getEndKey().getRow()));
+        TabletsSection.encodeRow(MetadataTable.ID, TabletsSection.getRange().getEndKey().getRow()));
 
     // table tablet's directory
     Key tableDirKey = new Key(tableExtent, ServerColumnFamily.DIRECTORY_COLUMN.getColumnFamily(),
@@ -2352,10 +2351,10 @@ public class RFileTest {
     // table tablet's prevRow
     Key tablePrevRowKey = new Key(tableExtent, TabletColumnFamily.PREV_ROW_COLUMN.getColumnFamily(),
         TabletColumnFamily.PREV_ROW_COLUMN.getColumnQualifier(), 0);
-    mfw.append(tablePrevRowKey, KeyExtent.encodePrevEndRow(null));
+    mfw.append(tablePrevRowKey, TabletColumnFamily.encodePrevEndRow(null));
 
     // ----------] default tablet info
-    Text defaultExtent = new Text(TabletsSection.getRow(MetadataTable.ID, null));
+    Text defaultExtent = new Text(TabletsSection.encodeRow(MetadataTable.ID, null));
 
     // default's directory
     Key defaultDirKey =
@@ -2373,7 +2372,7 @@ public class RFileTest {
         new Key(defaultExtent, TabletColumnFamily.PREV_ROW_COLUMN.getColumnFamily(),
             TabletColumnFamily.PREV_ROW_COLUMN.getColumnQualifier(), 0);
     mfw.append(defaultPrevRowKey,
-        KeyExtent.encodePrevEndRow(TabletsSection.getRange().getEndKey().getRow()));
+        TabletColumnFamily.encodePrevEndRow(TabletsSection.getRange().getEndKey().getRow()));
 
     testRfile.closeWriter();
 
diff --git a/core/src/test/java/org/apache/accumulo/core/metadata/schema/LinkingIteratorTest.java b/core/src/test/java/org/apache/accumulo/core/metadata/schema/LinkingIteratorTest.java
index bb49192..1d94536 100644
--- a/core/src/test/java/org/apache/accumulo/core/metadata/schema/LinkingIteratorTest.java
+++ b/core/src/test/java/org/apache/accumulo/core/metadata/schema/LinkingIteratorTest.java
@@ -54,8 +54,7 @@ public class LinkingIteratorTest {
     @Override
     public Iterator<TabletMetadata> apply(Range range) {
       Stream<TabletMetadata> stream = count++ == 0 ? initial.stream() : subsequent.stream();
-      return stream.filter(tm -> range.contains(new Key(tm.getExtent().getMetadataEntry())))
-          .iterator();
+      return stream.filter(tm -> range.contains(new Key(tm.getExtent().toMetaRow()))).iterator();
     }
   }
 
@@ -132,13 +131,13 @@ public class LinkingIteratorTest {
 
     check(tablets2, new IterFactory(tablets1, tablets2), TableId.of("4"));
     check(tablets2, new IterFactory(tablets1, tablets2),
-        new KeyExtent(TableId.of("4"), null, new Text("e")).toMetadataRange());
+        new KeyExtent(TableId.of("4"), null, new Text("e")).toMetaRange());
 
     // following should not care about missing tablet
     check(tablets1, new IterFactory(tablets1, tablets2),
-        new KeyExtent(TableId.of("4"), null, new Text("g")).toMetadataRange());
+        new KeyExtent(TableId.of("4"), null, new Text("g")).toMetaRange());
     check(tablets1, new IterFactory(tablets1, tablets2),
-        new KeyExtent(TableId.of("4"), null, new Text("f")).toMetadataRange());
+        new KeyExtent(TableId.of("4"), null, new Text("f")).toMetaRange());
   }
 
   @Test(expected = IllegalStateException.class)
@@ -161,6 +160,6 @@ public class LinkingIteratorTest {
     // tablets at end of table.
     List<TabletMetadata> tablets1 = Arrays.asList(create("4", null, "f"), create("4", "f", "m"));
     check(tablets1, new IterFactory(tablets1, tablets1),
-        new KeyExtent(TableId.of("4"), new Text("r"), new Text("e")).toMetadataRange());
+        new KeyExtent(TableId.of("4"), new Text("r"), new Text("e")).toMetaRange());
   }
 }
diff --git a/core/src/test/java/org/apache/accumulo/core/metadata/schema/MetadataSchemaTest.java b/core/src/test/java/org/apache/accumulo/core/metadata/schema/MetadataSchemaTest.java
new file mode 100644
index 0000000..f4c796f
--- /dev/null
+++ b/core/src/test/java/org/apache/accumulo/core/metadata/schema/MetadataSchemaTest.java
@@ -0,0 +1,41 @@
+/*
+ * 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.accumulo.core.metadata.schema;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import org.apache.accumulo.core.metadata.schema.MetadataSchema.TabletsSection.TabletColumnFamily;
+import org.apache.hadoop.io.Text;
+import org.junit.Test;
+
+public class MetadataSchemaTest {
+
+  @Test
+  public void testDecodeEncodePrevEndRow() {
+    assertNull(TabletColumnFamily.decodePrevEndRow(TabletColumnFamily.encodePrevEndRow(null)));
+
+    Text x = new Text();
+    assertEquals(x, TabletColumnFamily.decodePrevEndRow(TabletColumnFamily.encodePrevEndRow(x)));
+
+    Text ab = new Text("ab");
+    assertEquals(ab, TabletColumnFamily.decodePrevEndRow(TabletColumnFamily.encodePrevEndRow(ab)));
+  }
+
+}
diff --git a/core/src/test/java/org/apache/accumulo/core/metadata/schema/TabletMetadataTest.java b/core/src/test/java/org/apache/accumulo/core/metadata/schema/TabletMetadataTest.java
index 9efc990..1fd6085 100644
--- a/core/src/test/java/org/apache/accumulo/core/metadata/schema/TabletMetadataTest.java
+++ b/core/src/test/java/org/apache/accumulo/core/metadata/schema/TabletMetadataTest.java
@@ -46,6 +46,7 @@ import org.apache.accumulo.core.metadata.schema.MetadataSchema.TabletsSection.Da
 import org.apache.accumulo.core.metadata.schema.MetadataSchema.TabletsSection.FutureLocationColumnFamily;
 import org.apache.accumulo.core.metadata.schema.MetadataSchema.TabletsSection.LastLocationColumnFamily;
 import org.apache.accumulo.core.metadata.schema.MetadataSchema.TabletsSection.ScanFileColumnFamily;
+import org.apache.accumulo.core.metadata.schema.MetadataSchema.TabletsSection.TabletColumnFamily;
 import org.apache.accumulo.core.metadata.schema.TabletMetadata.ColumnType;
 import org.apache.accumulo.core.metadata.schema.TabletMetadata.LocationType;
 import org.apache.accumulo.core.tabletserver.log.LogEntry;
@@ -60,7 +61,7 @@ public class TabletMetadataTest {
   public void testAllColumns() {
     KeyExtent extent = new KeyExtent(TableId.of("5"), new Text("df"), new Text("da"));
 
-    Mutation mutation = extent.getPrevRowUpdateMutation();
+    Mutation mutation = TabletColumnFamily.createPrevRowMutation(extent);
 
     COMPACT_COLUMN.put(mutation, new Value("5"));
     DIRECTORY_COLUMN.put(mutation, new Value("t-0001757"));
@@ -107,7 +108,7 @@ public class TabletMetadataTest {
     assertEquals("OK", tm.getCloned());
     assertEquals(5L, tm.getCompactId().getAsLong());
     assertEquals("t-0001757", tm.getDirName());
-    assertEquals(extent.getEndRow(), tm.getEndRow());
+    assertEquals(extent.endRow(), tm.getEndRow());
     assertEquals(extent, tm.getExtent());
     assertEquals(Set.of(tf1, tf2), Set.copyOf(tm.getFiles()));
     assertEquals(Map.of(tf1, dfv1, tf2, dfv2), tm.getFilesMap());
@@ -124,8 +125,8 @@ public class TabletMetadataTest {
     assertEquals(LocationType.LAST, tm.getLast().getType());
     assertEquals(Set.of(le1.getName() + " " + le1.timestamp, le2.getName() + " " + le2.timestamp),
         tm.getLogs().stream().map(le -> le.getName() + " " + le.timestamp).collect(toSet()));
-    assertEquals(extent.getPrevEndRow(), tm.getPrevEndRow());
-    assertEquals(extent.getTableId(), tm.getTableId());
+    assertEquals(extent.prevEndRow(), tm.getPrevEndRow());
+    assertEquals(extent.tableId(), tm.getTableId());
     assertTrue(tm.sawPrevEndRow());
     assertEquals("M123456789", tm.getTime().encode());
     assertEquals(Set.of(sf1, sf2), Set.copyOf(tm.getScans()));
@@ -135,7 +136,7 @@ public class TabletMetadataTest {
   public void testFuture() {
     KeyExtent extent = new KeyExtent(TableId.of("5"), new Text("df"), new Text("da"));
 
-    Mutation mutation = extent.getPrevRowUpdateMutation();
+    Mutation mutation = TabletColumnFamily.createPrevRowMutation(extent);
     mutation.at().family(FutureLocationColumnFamily.NAME).qualifier("s001").put("server1:8555");
 
     SortedMap<Key,Value> rowMap = toRowMap(mutation);
@@ -154,7 +155,7 @@ public class TabletMetadataTest {
   public void testFutureAndCurrent() {
     KeyExtent extent = new KeyExtent(TableId.of("5"), new Text("df"), new Text("da"));
 
-    Mutation mutation = extent.getPrevRowUpdateMutation();
+    Mutation mutation = TabletColumnFamily.createPrevRowMutation(extent);
     mutation.at().family(CurrentLocationColumnFamily.NAME).qualifier("s001").put("server1:8555");
     mutation.at().family(FutureLocationColumnFamily.NAME).qualifier("s001").put("server1:8555");
 
diff --git a/server/tserver/src/test/java/org/apache/accumulo/tserver/log/LogEntryTest.java b/core/src/test/java/org/apache/accumulo/core/tabletserver/log/LogEntryTest.java
similarity index 52%
rename from server/tserver/src/test/java/org/apache/accumulo/tserver/log/LogEntryTest.java
rename to core/src/test/java/org/apache/accumulo/core/tabletserver/log/LogEntryTest.java
index 3b34c9c..1d25c94 100644
--- a/server/tserver/src/test/java/org/apache/accumulo/tserver/log/LogEntryTest.java
+++ b/core/src/test/java/org/apache/accumulo/core/tabletserver/log/LogEntryTest.java
@@ -16,23 +16,64 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.accumulo.tserver.log;
+package org.apache.accumulo.core.tabletserver.log;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotSame;
+
+import java.io.IOException;
+import java.util.Arrays;
 
 import org.apache.accumulo.core.data.Key;
 import org.apache.accumulo.core.data.TableId;
 import org.apache.accumulo.core.data.Value;
 import org.apache.accumulo.core.dataImpl.KeyExtent;
-import org.apache.accumulo.core.tabletserver.log.LogEntry;
 import org.apache.hadoop.io.Text;
 import org.junit.Test;
 
 public class LogEntryTest {
 
+  private static void compareLogEntries(LogEntry one, LogEntry two) throws IOException {
+    assertNotSame(one, two);
+    assertEquals(one.toString(), two.toString());
+    assertEquals(one.getColumnFamily(), two.getColumnFamily());
+    assertEquals(one.getColumnQualifier(), two.getColumnQualifier());
+    assertEquals(one.getName(), two.getName());
+    assertEquals(one.getRow(), two.getRow());
+    assertEquals(one.getUniqueID(), two.getUniqueID());
+    assertEquals(one.getValue(), two.getValue());
+    // arrays differ in serialized form because of the different prevEndRow, but that shouldn't
+    // matter for anything functionality in the LogEntry
+    assertFalse(Arrays.equals(one.toBytes(), two.toBytes()));
+  }
+
+  @Test
+  public void testPrevRowDoesntMatter() throws IOException {
+    long ts = 12345678L;
+    String server = "localhost:1234";
+    String filename = "default/foo";
+
+    // with no end row, different prev rows
+    LogEntry entry1 =
+        new LogEntry(new KeyExtent(TableId.of("1"), null, new Text("A")), ts, server, filename);
+    LogEntry entry2 =
+        new LogEntry(new KeyExtent(TableId.of("1"), null, new Text("B")), ts, server, filename);
+    assertEquals("1< default/foo", entry1.toString());
+    compareLogEntries(entry1, entry2);
+
+    // with same end row, different prev rows
+    LogEntry entry3 = new LogEntry(new KeyExtent(TableId.of("2"), new Text("same"), new Text("A")),
+        ts, server, filename);
+    LogEntry entry4 = new LogEntry(new KeyExtent(TableId.of("2"), new Text("same"), new Text("B")),
+        ts, server, filename);
+    assertEquals("2;same default/foo", entry3.toString());
+    compareLogEntries(entry3, entry4);
+  }
+
   @Test
   public void test() throws Exception {
-    KeyExtent extent = new KeyExtent(TableId.of("1"), null, new Text(""));
+    KeyExtent extent = new KeyExtent(TableId.of("1"), null, null);
     long ts = 12345678L;
     String server = "localhost:1234";
     String filename = "default/foo";
@@ -41,7 +82,7 @@ public class LogEntryTest {
     assertEquals(server, entry.server);
     assertEquals(filename, entry.filename);
     assertEquals(ts, entry.timestamp);
-    assertEquals("1<; default/foo", entry.toString());
+    assertEquals("1< default/foo", entry.toString());
     assertEquals(new Text("log"), entry.getColumnFamily());
     assertEquals(new Text("localhost:1234/default/foo"), entry.getColumnQualifier());
     LogEntry copy = LogEntry.fromBytes(entry.toBytes());
diff --git a/core/src/test/java/org/apache/accumulo/core/util/MergeTest.java b/core/src/test/java/org/apache/accumulo/core/util/MergeTest.java
index aa16c22..2af1619 100644
--- a/core/src/test/java/org/apache/accumulo/core/util/MergeTest.java
+++ b/core/src/test/java/org/apache/accumulo/core/util/MergeTest.java
@@ -71,13 +71,13 @@ public class MergeTest {
           while (impl.hasNext()) {
             Size candidate = impl.next();
             if (start != null) {
-              if (candidate.extent.getEndRow() != null
-                  && candidate.extent.getEndRow().compareTo(start) < 0)
+              if (candidate.extent.endRow() != null
+                  && candidate.extent.endRow().compareTo(start) < 0)
                 continue;
             }
             if (end != null) {
-              if (candidate.extent.getPrevEndRow() != null
-                  && candidate.extent.getPrevEndRow().compareTo(end) >= 0)
+              if (candidate.extent.prevEndRow() != null
+                  && candidate.extent.prevEndRow().compareTo(end) >= 0)
                 continue;
             }
             return candidate;
diff --git a/hadoop-mapreduce/src/main/java/org/apache/accumulo/hadoopImpl/mapreduce/lib/InputConfigurator.java b/hadoop-mapreduce/src/main/java/org/apache/accumulo/hadoopImpl/mapreduce/lib/InputConfigurator.java
index 3985f9a..5aaa773 100644
--- a/hadoop-mapreduce/src/main/java/org/apache/accumulo/hadoopImpl/mapreduce/lib/InputConfigurator.java
+++ b/hadoop-mapreduce/src/main/java/org/apache/accumulo/hadoopImpl/mapreduce/lib/InputConfigurator.java
@@ -852,7 +852,7 @@ public class InputConfigurator extends ConfiguratorBase {
         startRow = new Text();
 
       Range metadataRange =
-          new Range(new KeyExtent(tableId, startRow, null).getMetadataEntry(), true, null, false);
+          new Range(new KeyExtent(tableId, startRow, null).toMetaRow(), true, null, false);
       Scanner scanner = context.createScanner(MetadataTable.NAME, Authorizations.EMPTY);
       TabletColumnFamily.PREV_ROW_COLUMN.fetch(scanner);
       scanner.fetchColumnFamily(LastLocationColumnFamily.NAME);
@@ -882,7 +882,7 @@ public class InputConfigurator extends ConfiguratorBase {
           }
 
           if (TabletColumnFamily.PREV_ROW_COLUMN.hasColumns(key)) {
-            extent = new KeyExtent(key.getRow(), entry.getValue());
+            extent = KeyExtent.fromMetaPrevRow(entry);
           }
 
         }
@@ -890,7 +890,7 @@ public class InputConfigurator extends ConfiguratorBase {
         if (location != null)
           return null;
 
-        if (!extent.getTableId().equals(tableId)) {
+        if (!extent.tableId().equals(tableId)) {
           throw new AccumuloException("Saw unexpected table Id " + tableId + " " + extent);
         }
 
@@ -901,8 +901,8 @@ public class InputConfigurator extends ConfiguratorBase {
         binnedRanges.computeIfAbsent(last, k -> new HashMap<>())
             .computeIfAbsent(extent, k -> new ArrayList<>()).add(range);
 
-        if (extent.getEndRow() == null
-            || range.afterEndKey(new Key(extent.getEndRow()).followingKey(PartialKey.ROW))) {
+        if (extent.endRow() == null
+            || range.afterEndKey(new Key(extent.endRow()).followingKey(PartialKey.ROW))) {
           break;
         }
 
diff --git a/server/base/src/main/java/org/apache/accumulo/server/client/BulkImporter.java b/server/base/src/main/java/org/apache/accumulo/server/client/BulkImporter.java
index 2a3805c..e3a2bb5 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/client/BulkImporter.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/client/BulkImporter.java
@@ -621,11 +621,11 @@ public class BulkImporter {
       TabletLocator locator, Path file, KeyExtent failed) throws Exception {
     locator.invalidateCache(failed);
     Text start = getStartRowForExtent(failed);
-    return findOverlappingTablets(context, fs, locator, file, start, failed.getEndRow());
+    return findOverlappingTablets(context, fs, locator, file, start, failed.endRow());
   }
 
   protected static Text getStartRowForExtent(KeyExtent extent) {
-    Text start = extent.getPrevEndRow();
+    Text start = extent.prevEndRow();
     if (start != null) {
       start = new Text(start);
       // ACCUMULO-3967 We want the first possible key in this tablet, not the following row from the
@@ -661,7 +661,7 @@ public class BulkImporter {
         TabletLocation tabletLocation = locator.locateTablet(context, row, false, true);
         // log.debug(filename + " found row " + row + " at location " + tabletLocation);
         result.add(tabletLocation);
-        row = tabletLocation.tablet_extent.getEndRow();
+        row = tabletLocation.tablet_extent.endRow();
         if (row != null && (endRow == null || row.compareTo(endRow) < 0)) {
           row = new Text(row);
           row.append(byte0, 0, byte0.length);
diff --git a/server/base/src/main/java/org/apache/accumulo/server/constraints/MetadataConstraints.java b/server/base/src/main/java/org/apache/accumulo/server/constraints/MetadataConstraints.java
index 45c702d..c9acb53 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/constraints/MetadataConstraints.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/constraints/MetadataConstraints.java
@@ -263,12 +263,12 @@ public class MetadataConstraints implements Constraint {
         } else if (new ColumnFQ(columnUpdate).equals(TabletColumnFamily.PREV_ROW_COLUMN)
             && columnUpdate.getValue().length > 0
             && (violations == null || !violations.contains((short) 4))) {
-          KeyExtent ke = new KeyExtent(new Text(mutation.getRow()), (Text) null);
+          KeyExtent ke = KeyExtent.fromMetaRow(new Text(mutation.getRow()));
 
-          Text per = KeyExtent.decodePrevEndRow(new Value(columnUpdate.getValue()));
+          Text per = TabletColumnFamily.decodePrevEndRow(new Value(columnUpdate.getValue()));
 
           boolean prevEndRowLessThanEndRow =
-              per == null || ke.getEndRow() == null || per.compareTo(ke.getEndRow()) < 0;
+              per == null || ke.endRow() == null || per.compareTo(ke.endRow()) < 0;
 
           if (!prevEndRowLessThanEndRow) {
             violations = addViolation(violations, 3);
diff --git a/server/base/src/main/java/org/apache/accumulo/server/init/Initialize.java b/server/base/src/main/java/org/apache/accumulo/server/init/Initialize.java
index 3855892..d631983 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/init/Initialize.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/init/Initialize.java
@@ -53,7 +53,6 @@ import org.apache.accumulo.core.crypto.CryptoServiceFactory.ClassloaderType;
 import org.apache.accumulo.core.data.Key;
 import org.apache.accumulo.core.data.TableId;
 import org.apache.accumulo.core.data.Value;
-import org.apache.accumulo.core.dataImpl.KeyExtent;
 import org.apache.accumulo.core.file.FileOperations;
 import org.apache.accumulo.core.file.FileSKVWriter;
 import org.apache.accumulo.core.iterators.Combiner;
@@ -603,10 +602,10 @@ public class Initialize implements KeywordExecutable {
 
   private static void createEntriesForTablet(TreeMap<Key,Value> map, Tablet tablet) {
     Value EMPTY_SIZE = new DataFileValue(0, 0).encodeAsValue();
-    Text extent = new Text(TabletsSection.getRow(tablet.tableId, tablet.endRow));
+    Text extent = new Text(TabletsSection.encodeRow(tablet.tableId, tablet.endRow));
     addEntry(map, extent, DIRECTORY_COLUMN, new Value(tablet.dirName));
     addEntry(map, extent, TIME_COLUMN, new Value(new MetadataTime(0, TimeType.LOGICAL).encode()));
-    addEntry(map, extent, PREV_ROW_COLUMN, KeyExtent.encodePrevEndRow(tablet.prevEndRow));
+    addEntry(map, extent, PREV_ROW_COLUMN, TabletColumnFamily.encodePrevEndRow(tablet.prevEndRow));
     for (String file : tablet.files) {
       addEntry(map, extent, new ColumnFQ(DataFileColumnFamily.NAME, new Text(file)), EMPTY_SIZE);
     }
diff --git a/server/base/src/main/java/org/apache/accumulo/server/master/balancer/ChaoticLoadBalancer.java b/server/base/src/main/java/org/apache/accumulo/server/master/balancer/ChaoticLoadBalancer.java
index ecfa8aa..f8ca8b9 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/master/balancer/ChaoticLoadBalancer.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/master/balancer/ChaoticLoadBalancer.java
@@ -140,7 +140,7 @@ public class ChaoticLoadBalancer extends TabletBalancer {
           continue;
         try {
           for (TabletStats ts : getOnlineTabletsForTable(e.getKey(), id)) {
-            KeyExtent ke = new KeyExtent(ts.extent);
+            KeyExtent ke = KeyExtent.fromThrift(ts.extent);
             int index = r.nextInt(underCapacityTServer.size());
             TServerInstance dest = underCapacityTServer.get(index);
             if (dest.equals(e.getKey()))
diff --git a/server/base/src/main/java/org/apache/accumulo/server/master/balancer/DefaultLoadBalancer.java b/server/base/src/main/java/org/apache/accumulo/server/master/balancer/DefaultLoadBalancer.java
index ad96a4c..4573697 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/master/balancer/DefaultLoadBalancer.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/master/balancer/DefaultLoadBalancer.java
@@ -251,7 +251,7 @@ public class DefaultLoadBalancer extends TabletBalancer {
             return result;
           }
           for (TabletStats stat : stats)
-            onlineTabletsForTable.put(new KeyExtent(stat.extent), stat);
+            onlineTabletsForTable.put(KeyExtent.fromThrift(stat.extent), stat);
           donerTabletStats.put(table, onlineTabletsForTable);
         }
       } catch (Exception ex) {
diff --git a/server/base/src/main/java/org/apache/accumulo/server/master/balancer/GroupBalancer.java b/server/base/src/main/java/org/apache/accumulo/server/master/balancer/GroupBalancer.java
index c469932..71dcb70 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/master/balancer/GroupBalancer.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/master/balancer/GroupBalancer.java
@@ -121,7 +121,7 @@ public abstract class GroupBalancer extends TabletBalancer {
     }
 
     for (KeyExtent keyExtent : migrations) {
-      if (keyExtent.getTableId().equals(tableId)) {
+      if (keyExtent.tableId().equals(tableId)) {
         return false;
       }
     }
diff --git a/server/base/src/main/java/org/apache/accumulo/server/master/balancer/HostRegexTableLoadBalancer.java b/server/base/src/main/java/org/apache/accumulo/server/master/balancer/HostRegexTableLoadBalancer.java
index 14edfa8..c265b38 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/master/balancer/HostRegexTableLoadBalancer.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/master/balancer/HostRegexTableLoadBalancer.java
@@ -351,7 +351,7 @@ public class HostRegexTableLoadBalancer extends TableLoadBalancer {
     // group the unassigned into tables
     Map<TableId,Map<KeyExtent,TServerInstance>> groupedUnassigned = new HashMap<>();
     unassigned.forEach((keyExtent, tServerInstance) -> {
-      groupedUnassigned.computeIfAbsent(keyExtent.getTableId(), p -> new HashMap<>()).put(keyExtent,
+      groupedUnassigned.computeIfAbsent(keyExtent.tableId(), p -> new HashMap<>()).put(keyExtent,
           tServerInstance);
     });
 
@@ -427,7 +427,7 @@ public class HostRegexTableLoadBalancer extends TableLoadBalancer {
               }
               Random random = new SecureRandom();
               for (TabletStats ts : outOfBoundsTablets) {
-                KeyExtent ke = new KeyExtent(ts.getExtent());
+                KeyExtent ke = KeyExtent.fromThrift(ts.getExtent());
                 if (migrations.contains(ke)) {
                   LOG.debug("Migration for out of bounds tablet {} has already been requested", ke);
                   continue;
@@ -489,12 +489,12 @@ public class HostRegexTableLoadBalancer extends TableLoadBalancer {
       Multimap<TServerInstance,String> serverTableIdCopied = HashMultimap.create();
       for (TabletMigration migration : migrationsFromLastPass.values()) {
         TableInfo fromInfo = getTableInfo(currentCopy, serverTableIdCopied,
-            migration.tablet.getTableId().toString(), migration.oldServer);
+            migration.tablet.tableId().toString(), migration.oldServer);
         if (fromInfo != null) {
           fromInfo.setOnlineTablets(fromInfo.getOnlineTablets() - 1);
         }
         TableInfo toInfo = getTableInfo(currentCopy, serverTableIdCopied,
-            migration.tablet.getTableId().toString(), migration.newServer);
+            migration.tablet.tableId().toString(), migration.newServer);
         if (toInfo != null) {
           toInfo.setOnlineTablets(toInfo.getOnlineTablets() + 1);
         }
diff --git a/server/base/src/main/java/org/apache/accumulo/server/master/balancer/RegexGroupBalancer.java b/server/base/src/main/java/org/apache/accumulo/server/master/balancer/RegexGroupBalancer.java
index a6a4e48..d116112 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/master/balancer/RegexGroupBalancer.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/master/balancer/RegexGroupBalancer.java
@@ -86,7 +86,7 @@ public class RegexGroupBalancer extends GroupBalancer {
 
       @Override
       public String apply(KeyExtent input) {
-        Text er = input.getEndRow();
+        Text er = input.endRow();
         if (er == null) {
           return defaultGroup;
         }
diff --git a/server/base/src/main/java/org/apache/accumulo/server/master/balancer/TableLoadBalancer.java b/server/base/src/main/java/org/apache/accumulo/server/master/balancer/TableLoadBalancer.java
index 0872847..d5008f9 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/master/balancer/TableLoadBalancer.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/master/balancer/TableLoadBalancer.java
@@ -117,7 +117,7 @@ public class TableLoadBalancer extends TabletBalancer {
     // separate the unassigned into tables
     Map<TableId,Map<KeyExtent,TServerInstance>> groupedUnassigned = new HashMap<>();
     unassigned.forEach((keyExtent, tServerInstance) -> {
-      groupedUnassigned.computeIfAbsent(keyExtent.getTableId(), p -> new HashMap<>()).put(keyExtent,
+      groupedUnassigned.computeIfAbsent(keyExtent.tableId(), p -> new HashMap<>()).put(keyExtent,
           tServerInstance);
     });
 
diff --git a/server/base/src/main/java/org/apache/accumulo/server/master/state/MergeInfo.java b/server/base/src/main/java/org/apache/accumulo/server/master/state/MergeInfo.java
index d6d28f3..8e8f664 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/master/state/MergeInfo.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/master/state/MergeInfo.java
@@ -44,15 +44,14 @@ public class MergeInfo implements Writable {
 
   @Override
   public void readFields(DataInput in) throws IOException {
-    extent = new KeyExtent();
-    extent.readFields(in);
+    extent = KeyExtent.readFrom(in);
     state = MergeState.values()[in.readInt()];
     operation = Operation.values()[in.readInt()];
   }
 
   @Override
   public void write(DataOutput out) throws IOException {
-    extent.write(out);
+    extent.writeTo(out);
     out.writeInt(state.ordinal());
     out.writeInt(operation.ordinal());
   }
@@ -85,11 +84,10 @@ public class MergeInfo implements Writable {
   public boolean needsToBeChopped(KeyExtent otherExtent) {
     // During a delete, the block after the merge will be stretched to cover the deleted area.
     // Therefore, it needs to be chopped
-    if (!otherExtent.getTableId().equals(extent.getTableId()))
+    if (!otherExtent.tableId().equals(extent.tableId()))
       return false;
     if (isDelete())
-      return otherExtent.getPrevEndRow() != null
-          && otherExtent.getPrevEndRow().equals(extent.getEndRow());
+      return otherExtent.prevEndRow() != null && otherExtent.prevEndRow().equals(extent.endRow());
     else
       return this.extent.overlaps(otherExtent);
   }
diff --git a/server/base/src/main/java/org/apache/accumulo/server/master/state/MetaDataStateStore.java b/server/base/src/main/java/org/apache/accumulo/server/master/state/MetaDataStateStore.java
index 48f003e..a3d1c42 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/master/state/MetaDataStateStore.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/master/state/MetaDataStateStore.java
@@ -63,7 +63,7 @@ class MetaDataStateStore implements TabletStateStore {
     BatchWriter writer = createBatchWriter();
     try {
       for (Assignment assignment : assignments) {
-        Mutation m = new Mutation(assignment.tablet.getMetadataEntry());
+        Mutation m = new Mutation(assignment.tablet.toMetaRow());
         assignment.server.putLocation(m);
         assignment.server.putLastLocation(m);
         assignment.server.clearFutureLocation(m);
@@ -97,7 +97,7 @@ class MetaDataStateStore implements TabletStateStore {
     BatchWriter writer = createBatchWriter();
     try {
       for (Assignment assignment : assignments) {
-        Mutation m = new Mutation(assignment.tablet.getMetadataEntry());
+        Mutation m = new Mutation(assignment.tablet.toMetaRow());
         SuspendingTServer.clearSuspension(m);
         assignment.server.putFutureLocation(m);
         writer.addMutation(m);
@@ -132,7 +132,7 @@ class MetaDataStateStore implements TabletStateStore {
     BatchWriter writer = createBatchWriter();
     try {
       for (TabletLocationState tls : tablets) {
-        Mutation m = new Mutation(tls.extent.getMetadataEntry());
+        Mutation m = new Mutation(tls.extent.toMetaRow());
         if (tls.current != null) {
           tls.current.clearLocation(m);
           if (logsForDeadServers != null) {
@@ -178,7 +178,7 @@ class MetaDataStateStore implements TabletStateStore {
         if (tls.suspend != null) {
           continue;
         }
-        Mutation m = new Mutation(tls.extent.getMetadataEntry());
+        Mutation m = new Mutation(tls.extent.toMetaRow());
         SuspendingTServer.clearSuspension(m);
         writer.addMutation(m);
       }
diff --git a/server/base/src/main/java/org/apache/accumulo/server/master/state/MetaDataTableScanner.java b/server/base/src/main/java/org/apache/accumulo/server/master/state/MetaDataTableScanner.java
index 4b6ae1c..e97acae 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/master/state/MetaDataTableScanner.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/master/state/MetaDataTableScanner.java
@@ -160,15 +160,15 @@ public class MetaDataTableScanner implements ClosableIterator<TabletLocationStat
       if (cf.compareTo(FutureLocationColumnFamily.NAME) == 0) {
         TServerInstance location = new TServerInstance(entry.getValue(), cq);
         if (future != null) {
-          throw new BadLocationStateException("found two assignments for the same extent "
-              + key.getRow() + ": " + future + " and " + location, entry.getKey().getRow());
+          throw new BadLocationStateException("found two assignments for the same extent " + row
+              + ": " + future + " and " + location, row);
         }
         future = location;
       } else if (cf.compareTo(CurrentLocationColumnFamily.NAME) == 0) {
         TServerInstance location = new TServerInstance(entry.getValue(), cq);
         if (current != null) {
-          throw new BadLocationStateException("found two locations for the same extent "
-              + key.getRow() + ": " + current + " and " + location, entry.getKey().getRow());
+          throw new BadLocationStateException("found two locations for the same extent " + row
+              + ": " + current + " and " + location, row);
         }
         current = location;
       } else if (cf.compareTo(LogColumnFamily.NAME) == 0) {
@@ -181,7 +181,7 @@ public class MetaDataTableScanner implements ClosableIterator<TabletLocationStat
       } else if (cf.compareTo(ChoppedColumnFamily.NAME) == 0) {
         chopped = true;
       } else if (TabletColumnFamily.PREV_ROW_COLUMN.equals(cf, cq)) {
-        extent = new KeyExtent(row, entry.getValue());
+        extent = KeyExtent.fromMetaPrevRow(entry);
       } else if (SuspendLocationColumn.SUSPEND_COLUMN.equals(cf, cq)) {
         suspend = SuspendingTServer.fromValue(entry.getValue());
       }
diff --git a/server/base/src/main/java/org/apache/accumulo/server/master/state/TabletLocationState.java b/server/base/src/main/java/org/apache/accumulo/server/master/state/TabletLocationState.java
index bb87b20..c3a96aa 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/master/state/TabletLocationState.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/master/state/TabletLocationState.java
@@ -63,7 +63,7 @@ public class TabletLocationState {
     if (current != null && future != null) {
       throw new BadLocationStateException(
           extent + " is both assigned and hosted, which should never happen: " + this,
-          extent.getMetadataEntry());
+          extent.toMetaRow());
     }
   }
 
diff --git a/server/base/src/main/java/org/apache/accumulo/server/master/state/TabletStateChangeIterator.java b/server/base/src/main/java/org/apache/accumulo/server/master/state/TabletStateChangeIterator.java
index d4ea5aa..e5784ed 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/master/state/TabletStateChangeIterator.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/master/state/TabletStateChangeIterator.java
@@ -97,9 +97,7 @@ public class TabletStateChangeIterator extends SkippingIterator {
       byte[] data = Base64.getDecoder().decode(migrations);
       buffer.reset(data, data.length);
       while (buffer.available() > 0) {
-        KeyExtent extent = new KeyExtent();
-        extent.readFields(buffer);
-        result.add(extent);
+        result.add(KeyExtent.readFrom(buffer));
       }
       return result;
     } catch (Exception ex) {
@@ -145,7 +143,7 @@ public class TabletStateChangeIterator extends SkippingIterator {
       while (buffer.available() > 0) {
         MergeInfo mergeInfo = new MergeInfo();
         mergeInfo.readFields(buffer);
-        result.put(mergeInfo.extent.getTableId(), mergeInfo);
+        result.put(mergeInfo.extent.tableId(), mergeInfo);
       }
       return result;
     } catch (Exception ex) {
@@ -172,7 +170,7 @@ public class TabletStateChangeIterator extends SkippingIterator {
         return;
       }
       // we always want data about merges
-      MergeInfo merge = merges.get(tls.extent.getTableId());
+      MergeInfo merge = merges.get(tls.extent.tableId());
       if (merge != null) {
         // could make this smarter by only returning if the tablet is involved in the merge
         return;
@@ -183,7 +181,7 @@ public class TabletStateChangeIterator extends SkippingIterator {
       }
 
       // is the table supposed to be online or offline?
-      boolean shouldBeOnline = onlineTables.contains(tls.extent.getTableId());
+      boolean shouldBeOnline = onlineTables.contains(tls.extent.tableId());
 
       if (debug) {
         log.debug("{} is {} and should be {} line", tls.extent, tls.getState(current),
@@ -253,7 +251,7 @@ public class TabletStateChangeIterator extends SkippingIterator {
     DataOutputBuffer buffer = new DataOutputBuffer();
     try {
       for (KeyExtent extent : migrations) {
-        extent.write(buffer);
+        extent.writeTo(buffer);
       }
     } catch (Exception ex) {
       throw new RuntimeException(ex);
diff --git a/server/base/src/main/java/org/apache/accumulo/server/master/state/TabletStateStore.java b/server/base/src/main/java/org/apache/accumulo/server/master/state/TabletStateStore.java
index e74c9ec..2b6f4f3 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/master/state/TabletStateStore.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/master/state/TabletStateStore.java
@@ -99,7 +99,7 @@ public interface TabletStateStore extends Iterable<TabletLocationState> {
   }
 
   static TabletStateStore getStoreForTablet(KeyExtent extent, ServerContext context) {
-    return getStoreForLevel(DataLevel.of(extent.getTableId()), context);
+    return getStoreForLevel(DataLevel.of(extent.tableId()), context);
   }
 
   public static TabletStateStore getStoreForLevel(DataLevel level, ClientContext context) {
diff --git a/server/base/src/main/java/org/apache/accumulo/server/metadata/TabletMutatorBase.java b/server/base/src/main/java/org/apache/accumulo/server/metadata/TabletMutatorBase.java
index b1a0781..3bb3ebb 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/metadata/TabletMutatorBase.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/metadata/TabletMutatorBase.java
@@ -56,14 +56,14 @@ public abstract class TabletMutatorBase implements Ample.TabletMutator {
   protected TabletMutatorBase(ServerContext ctx, KeyExtent extent) {
     this.extent = extent;
     this.context = ctx;
-    mutation = new Mutation(extent.getMetadataEntry());
+    mutation = new Mutation(extent.toMetaRow());
   }
 
   @Override
   public Ample.TabletMutator putPrevEndRow(Text per) {
     Preconditions.checkState(updatesEnabled, "Cannot make updates after calling mutate.");
     TabletColumnFamily.PREV_ROW_COLUMN.put(mutation,
-        KeyExtent.encodePrevEndRow(extent.getPrevEndRow()));
+        TabletColumnFamily.encodePrevEndRow(extent.prevEndRow()));
     return this;
   }
 
diff --git a/server/base/src/main/java/org/apache/accumulo/server/metadata/TabletsMutatorImpl.java b/server/base/src/main/java/org/apache/accumulo/server/metadata/TabletsMutatorImpl.java
index f8f7d7d..794f165 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/metadata/TabletsMutatorImpl.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/metadata/TabletsMutatorImpl.java
@@ -70,7 +70,7 @@ public class TabletsMutatorImpl implements TabletsMutator {
     if (extent.isRootTablet()) {
       return new RootTabletMutatorImpl(context);
     } else {
-      return new TabletMutatorImpl(context, extent, getWriter(extent.getTableId()));
+      return new TabletMutatorImpl(context, extent, getWriter(extent.tableId()));
     }
   }
 
diff --git a/server/base/src/main/java/org/apache/accumulo/server/tabletserver/LargestFirstMemoryManager.java b/server/base/src/main/java/org/apache/accumulo/server/tabletserver/LargestFirstMemoryManager.java
index a41ca6b..3379766 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/tabletserver/LargestFirstMemoryManager.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/tabletserver/LargestFirstMemoryManager.java
@@ -135,7 +135,7 @@ public class LargestFirstMemoryManager {
   }
 
   protected long getMinCIdleThreshold(KeyExtent extent) {
-    TableId tableId = extent.getTableId();
+    TableId tableId = extent.tableId();
     if (!mincIdleThresholds.containsKey(tableId))
       mincIdleThresholds.put(tableId, context.getTableConfiguration(tableId)
           .getTimeInMillis(Property.TABLE_MINC_COMPACT_IDLETIME));
@@ -169,7 +169,7 @@ public class LargestFirstMemoryManager {
     // find the largest and most idle tablets
     for (TabletState ts : tablets) {
       // Make sure that the table still exists
-      if (!tableExists(ts.getExtent().getTableId())) {
+      if (!tableExists(ts.getExtent().tableId())) {
         log.trace("Ignoring extent for deleted table: {}", ts.getExtent());
         continue;
       }
diff --git a/server/base/src/main/java/org/apache/accumulo/server/util/CheckForMetadataProblems.java b/server/base/src/main/java/org/apache/accumulo/server/util/CheckForMetadataProblems.java
index e77e681..ecdcff3 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/util/CheckForMetadataProblems.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/util/CheckForMetadataProblems.java
@@ -22,13 +22,13 @@ import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
 import java.util.Map.Entry;
-import java.util.Set;
 import java.util.TreeSet;
 
 import org.apache.accumulo.core.client.Accumulo;
 import org.apache.accumulo.core.client.AccumuloClient;
 import org.apache.accumulo.core.client.Scanner;
 import org.apache.accumulo.core.data.Key;
+import org.apache.accumulo.core.data.TableId;
 import org.apache.accumulo.core.data.Value;
 import org.apache.accumulo.core.dataImpl.KeyExtent;
 import org.apache.accumulo.core.metadata.MetadataTable;
@@ -44,61 +44,61 @@ import org.apache.htrace.TraceScope;
 public class CheckForMetadataProblems {
   private static boolean sawProblems = false;
 
-  public static void checkTable(String tablename, TreeSet<KeyExtent> tablets) {
+  private static void checkTable(TableId tableId, TreeSet<KeyExtent> tablets) {
     // sanity check of metadata table entries
     // make sure tablets has no holes, and that it starts and ends w/ null
 
     if (tablets.isEmpty()) {
-      System.out.println("No entries found in metadata table for table " + tablename);
+      System.out.println("No entries found in metadata table for table " + tableId);
       sawProblems = true;
       return;
     }
 
-    if (tablets.first().getPrevEndRow() != null) {
-      System.out.println("First entry for table " + tablename + "- " + tablets.first()
+    if (tablets.first().prevEndRow() != null) {
+      System.out.println("First entry for table " + tableId + "- " + tablets.first()
           + " - has non null prev end row");
       sawProblems = true;
       return;
     }
 
-    if (tablets.last().getEndRow() != null) {
+    if (tablets.last().endRow() != null) {
       System.out.println(
-          "Last entry for table " + tablename + "- " + tablets.last() + " - has non null end row");
+          "Last entry for table " + tableId + "- " + tablets.last() + " - has non null end row");
       sawProblems = true;
       return;
     }
 
     Iterator<KeyExtent> tabIter = tablets.iterator();
-    Text lastEndRow = tabIter.next().getEndRow();
+    Text lastEndRow = tabIter.next().endRow();
     boolean everythingLooksGood = true;
     while (tabIter.hasNext()) {
       KeyExtent tabke = tabIter.next();
       boolean broke = false;
-      if (tabke.getPrevEndRow() == null) {
+      if (tabke.prevEndRow() == null) {
         System.out
-            .println("Table " + tablename + " has null prev end row in middle of table " + tabke);
+            .println("Table " + tableId + " has null prev end row in middle of table " + tabke);
         broke = true;
-      } else if (!tabke.getPrevEndRow().equals(lastEndRow)) {
+      } else if (!tabke.prevEndRow().equals(lastEndRow)) {
         System.out.println(
-            "Table " + tablename + " has a hole " + tabke.getPrevEndRow() + " != " + lastEndRow);
+            "Table " + tableId + " has a hole " + tabke.prevEndRow() + " != " + lastEndRow);
         broke = true;
       }
       if (broke) {
         everythingLooksGood = false;
       }
 
-      lastEndRow = tabke.getEndRow();
+      lastEndRow = tabke.endRow();
     }
     if (everythingLooksGood)
-      System.out.println("All is well for table " + tablename);
+      System.out.println("All is well for table " + tableId);
     else
       sawProblems = true;
   }
 
-  public static void checkMetadataAndRootTableEntries(String tableNameToCheck, ServerUtilOpts opts)
+  private static void checkMetadataAndRootTableEntries(String tableNameToCheck, ServerUtilOpts opts)
       throws Exception {
     System.out.println("Checking table: " + tableNameToCheck);
-    Map<String,TreeSet<KeyExtent>> tables = new HashMap<>();
+    Map<TableId,TreeSet<KeyExtent>> tables = new HashMap<>();
 
     try (AccumuloClient client = Accumulo.newClient().from(opts.getClientProps()).build()) {
 
@@ -120,25 +120,21 @@ public class CheckForMetadataProblems {
 
         count++;
 
-        String tableName =
-            (new KeyExtent(entry.getKey().getRow(), (Text) null)).getTableId().canonical();
+        TableId tableId = KeyExtent.fromMetaRow(entry.getKey().getRow()).tableId();
 
-        TreeSet<KeyExtent> tablets = tables.get(tableName);
+        TreeSet<KeyExtent> tablets = tables.get(tableId);
         if (tablets == null) {
-          Set<Entry<String,TreeSet<KeyExtent>>> es = tables.entrySet();
 
-          for (Entry<String,TreeSet<KeyExtent>> entry2 : es) {
-            checkTable(entry2.getKey(), entry2.getValue());
-          }
+          tables.forEach(CheckForMetadataProblems::checkTable);
 
           tables.clear();
 
           tablets = new TreeSet<>();
-          tables.put(tableName, tablets);
+          tables.put(tableId, tablets);
         }
 
         if (TabletColumnFamily.PREV_ROW_COLUMN.equals(colf, colq)) {
-          KeyExtent tabletKe = new KeyExtent(entry.getKey().getRow(), entry.getValue());
+          KeyExtent tabletKe = KeyExtent.fromMetaPrevRow(entry);
           tablets.add(tabletKe);
           justLoc = false;
         } else if (colf.equals(CurrentLocationColumnFamily.NAME)) {
@@ -156,11 +152,7 @@ public class CheckForMetadataProblems {
       }
     }
 
-    Set<Entry<String,TreeSet<KeyExtent>>> es = tables.entrySet();
-
-    for (Entry<String,TreeSet<KeyExtent>> entry : es) {
-      checkTable(entry.getKey(), entry.getValue());
-    }
+    tables.forEach(CheckForMetadataProblems::checkTable);
 
     if (!sawProblems) {
       System.out.println("No problems found");
diff --git a/server/base/src/main/java/org/apache/accumulo/server/util/FindOfflineTablets.java b/server/base/src/main/java/org/apache/accumulo/server/util/FindOfflineTablets.java
index b146ab1..1920c3f 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/util/FindOfflineTablets.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/util/FindOfflineTablets.java
@@ -99,7 +99,7 @@ public class FindOfflineTablets {
     Range range = TabletsSection.getRange();
     if (tableName != null) {
       TableId tableId = Tables.getTableId(context, tableName);
-      range = new KeyExtent(tableId, null, null).toMetadataRange();
+      range = new KeyExtent(tableId, null, null).toMetaRange();
     }
 
     try (MetaDataTableScanner metaScanner =
@@ -116,7 +116,7 @@ public class FindOfflineTablets {
       TabletLocationState locationState = scanner.next();
       TabletState state = locationState.getState(tservers.getCurrentServers());
       if (state != null && state != TabletState.HOSTED
-          && context.getTableManager().getTableState(locationState.extent.getTableId())
+          && context.getTableManager().getTableState(locationState.extent.tableId())
               != TableState.OFFLINE) {
         System.out
             .println(locationState + " is " + state + "  #walogs:" + locationState.walogs.size());
diff --git a/server/base/src/main/java/org/apache/accumulo/server/util/MasterMetadataUtil.java b/server/base/src/main/java/org/apache/accumulo/server/util/MasterMetadataUtil.java
index 976e909..55f8a1f 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/util/MasterMetadataUtil.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/util/MasterMetadataUtil.java
@@ -69,7 +69,7 @@ public class MasterMetadataUtil {
       long lastFlushID, long lastCompactID, ZooLock zooLock) {
 
     TabletMutator tablet = context.getAmple().mutateTablet(extent);
-    tablet.putPrevEndRow(extent.getPrevEndRow());
+    tablet.putPrevEndRow(extent.prevEndRow());
     tablet.putZooLock(zooLock);
     tablet.putDirName(dirName);
     tablet.putTime(time);
@@ -110,8 +110,8 @@ public class MasterMetadataUtil {
           "Metadata entry does not have time (" + meta.getExtent() + ")");
     }
 
-    return fixSplit(context, meta.getTableId(), meta.getExtent().getMetadataEntry(),
-        meta.getPrevEndRow(), meta.getOldPrevEndRow(), meta.getSplitRatio(), lock);
+    return fixSplit(context, meta.getTableId(), meta.getExtent().toMetaRow(), meta.getPrevEndRow(),
+        meta.getOldPrevEndRow(), meta.getSplitRatio(), lock);
   }
 
   private static KeyExtent fixSplit(ServerContext context, TableId tableId, Text metadataEntry,
@@ -124,7 +124,7 @@ public class MasterMetadataUtil {
           "Split tablet does not have prev end row, something is amiss, extent = " + metadataEntry);
 
     // check to see if prev tablet exist in metadata tablet
-    Key prevRowKey = new Key(new Text(TabletsSection.getRow(tableId, metadataPrevEndRow)));
+    Key prevRowKey = new Key(new Text(TabletsSection.encodeRow(tableId, metadataPrevEndRow)));
 
     try (ScannerImpl scanner2 = new ScannerImpl(context, MetadataTable.ID, Authorizations.EMPTY)) {
       scanner2.setRange(new Range(prevRowKey, prevRowKey.followingKey(PartialKey.ROW)));
@@ -138,8 +138,8 @@ public class MasterMetadataUtil {
         SortedMap<StoredTabletFile,DataFileValue> highDatafileSizes = new TreeMap<>();
         SortedMap<StoredTabletFile,DataFileValue> lowDatafileSizes = new TreeMap<>();
 
+        Key rowKey = new Key(metadataEntry);
         try (Scanner scanner3 = new ScannerImpl(context, MetadataTable.ID, Authorizations.EMPTY)) {
-          Key rowKey = new Key(metadataEntry);
 
           scanner3.fetchColumnFamily(DataFileColumnFamily.NAME);
           scanner3.setRange(new Range(rowKey, rowKey.followingKey(PartialKey.ROW)));
@@ -159,11 +159,11 @@ public class MasterMetadataUtil {
         MetadataTableUtil.finishSplit(metadataEntry, highDatafileSizes, highDatafilesToRemove,
             context, lock);
 
-        return new KeyExtent(metadataEntry, KeyExtent.encodePrevEndRow(metadataPrevEndRow));
+        return KeyExtent.fromMetaRow(rowKey.getRow(), metadataPrevEndRow);
       } else {
         log.info("Rolling back incomplete split {} {}", metadataEntry, metadataPrevEndRow);
         MetadataTableUtil.rollBackSplit(metadataEntry, oper, context, lock);
-        return new KeyExtent(metadataEntry, oper);
+        return KeyExtent.fromMetaRow(metadataEntry, oper);
       }
     }
   }
@@ -184,7 +184,7 @@ public class MasterMetadataUtil {
       Long compactionId, DataFileValue size, String address, TServerInstance lastLocation,
       ZooLock zooLock) {
 
-    context.getAmple().putGcCandidates(extent.getTableId(), datafilesToDelete);
+    context.getAmple().putGcCandidates(extent.tableId(), datafilesToDelete);
 
     TabletMutator tablet = context.getAmple().mutateTablet(extent);
 
diff --git a/server/base/src/main/java/org/apache/accumulo/server/util/MetadataTableUtil.java b/server/base/src/main/java/org/apache/accumulo/server/util/MetadataTableUtil.java
index 00aac84..016d558 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/util/MetadataTableUtil.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/util/MetadataTableUtil.java
@@ -209,7 +209,7 @@ public class MetadataTableUtil {
   public static void addTablet(KeyExtent extent, String path, ServerContext context,
       TimeType timeType, ZooLock zooLock) {
     TabletMutator tablet = context.getAmple().mutateTablet(extent);
-    tablet.putPrevEndRow(extent.getPrevEndRow());
+    tablet.putPrevEndRow(extent.prevEndRow());
     tablet.putDirName(path);
     tablet.putTime(new MetadataTime(0, timeType));
     tablet.putZooLock(zooLock);
@@ -235,20 +235,21 @@ public class MetadataTableUtil {
 
   public static void rollBackSplit(Text metadataEntry, Text oldPrevEndRow, ServerContext context,
       ZooLock zooLock) {
-    KeyExtent ke = new KeyExtent(metadataEntry, oldPrevEndRow);
-    Mutation m = ke.getPrevRowUpdateMutation();
+    KeyExtent ke = KeyExtent.fromMetaRow(metadataEntry, oldPrevEndRow);
+    Mutation m = TabletColumnFamily.createPrevRowMutation(ke);
     TabletColumnFamily.SPLIT_RATIO_COLUMN.putDelete(m);
     TabletColumnFamily.OLD_PREV_ROW_COLUMN.putDelete(m);
-    update(context, zooLock, m, new KeyExtent(metadataEntry, (Text) null));
+    update(context, zooLock, m, KeyExtent.fromMetaRow(metadataEntry));
   }
 
   public static void splitTablet(KeyExtent extent, Text oldPrevEndRow, double splitRatio,
       ServerContext context, ZooLock zooLock) {
-    Mutation m = extent.getPrevRowUpdateMutation(); //
+    Mutation m = TabletColumnFamily.createPrevRowMutation(extent);
 
     TabletColumnFamily.SPLIT_RATIO_COLUMN.put(m, new Value(Double.toString(splitRatio)));
 
-    TabletColumnFamily.OLD_PREV_ROW_COLUMN.put(m, KeyExtent.encodePrevEndRow(oldPrevEndRow));
+    TabletColumnFamily.OLD_PREV_ROW_COLUMN.put(m,
+        TabletColumnFamily.encodePrevEndRow(oldPrevEndRow));
     ChoppedColumnFamily.CHOPPED_COLUMN.putDelete(m);
     update(context, zooLock, m, extent);
   }
@@ -270,13 +271,13 @@ public class MetadataTableUtil {
       m.putDelete(DataFileColumnFamily.NAME, pathToRemove.getMetaUpdateDeleteText());
     }
 
-    update(context, zooLock, m, new KeyExtent(metadataEntry, (Text) null));
+    update(context, zooLock, m, KeyExtent.fromMetaRow(metadataEntry));
   }
 
   public static void finishSplit(KeyExtent extent,
       Map<StoredTabletFile,DataFileValue> datafileSizes,
       List<StoredTabletFile> highDatafilesToRemove, ServerContext context, ZooLock zooLock) {
-    finishSplit(extent.getMetadataEntry(), datafileSizes, highDatafilesToRemove, context, zooLock);
+    finishSplit(extent.toMetaRow(), datafileSizes, highDatafilesToRemove, context, zooLock);
   }
 
   /**
@@ -364,7 +365,7 @@ public class MetadataTableUtil {
 
       // scan metadata for our table and delete everything we find
       Mutation m = null;
-      ms.setRange(new KeyExtent(tableId, null, null).toMetadataRange());
+      ms.setRange(new KeyExtent(tableId, null, null).toMetaRange());
 
       // insert deletes before deleting data from metadata... this makes the code fault tolerant
       if (insertDeletes) {
@@ -444,8 +445,8 @@ public class MetadataTableUtil {
   private static Mutation createCloneMutation(TableId srcTableId, TableId tableId,
       Map<Key,Value> tablet) {
 
-    KeyExtent ke = new KeyExtent(tablet.keySet().iterator().next().getRow(), (Text) null);
-    Mutation m = new Mutation(TabletsSection.getRow(tableId, ke.getEndRow()));
+    KeyExtent ke = KeyExtent.fromMetaRow(tablet.keySet().iterator().next().getRow());
+    Mutation m = new Mutation(TabletsSection.encodeRow(tableId, ke.endRow()));
 
     for (Entry<Key,Value> entry : tablet.entrySet()) {
       if (entry.getKey().getColumnFamily().equals(DataFileColumnFamily.NAME)) {
@@ -565,12 +566,12 @@ public class MetadataTableUtil {
 
       if (srcFiles.containsAll(cloneFiles)) {
         // write out marker that this tablet was successfully cloned
-        Mutation m = new Mutation(cloneTablet.getExtent().getMetadataEntry());
+        Mutation m = new Mutation(cloneTablet.getExtent().toMetaRow());
         m.put(ClonedColumnFamily.NAME, new Text(""), new Value("OK"));
         bw.addMutation(m);
       } else {
         // delete existing cloned tablet entry
-        Mutation m = new Mutation(cloneTablet.getExtent().getMetadataEntry());
+        Mutation m = new Mutation(cloneTablet.getExtent().toMetaRow());
 
         for (Entry<Key,Value> entry : cloneTablet.getKeyValues().entrySet()) {
           Key k = entry.getKey();
@@ -629,7 +630,7 @@ public class MetadataTableUtil {
 
       // delete the clone markers and create directory entries
       Scanner mscanner = context.createScanner(MetadataTable.NAME, Authorizations.EMPTY);
-      mscanner.setRange(new KeyExtent(tableId, null, null).toMetadataRange());
+      mscanner.setRange(new KeyExtent(tableId, null, null).toMetaRange());
       mscanner.fetchColumnFamily(ClonedColumnFamily.NAME);
 
       int dirCount = 0;
@@ -660,7 +661,7 @@ public class MetadataTableUtil {
         Scanner mscanner =
             new IsolatedScanner(client.createScanner(MetadataTable.NAME, Authorizations.EMPTY));
         BatchWriter bw = client.createBatchWriter(MetadataTable.NAME, new BatchWriterConfig())) {
-      mscanner.setRange(new KeyExtent(tableId, null, null).toMetadataRange());
+      mscanner.setRange(new KeyExtent(tableId, null, null).toMetaRange());
       mscanner.fetchColumnFamily(BulkFileColumnFamily.NAME);
 
       for (Entry<Key,Value> entry : mscanner) {
diff --git a/server/base/src/main/java/org/apache/accumulo/server/util/RemoveEntriesForMissingFiles.java b/server/base/src/main/java/org/apache/accumulo/server/util/RemoveEntriesForMissingFiles.java
index 5239b8d..dc1705d 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/util/RemoveEntriesForMissingFiles.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/util/RemoveEntriesForMissingFiles.java
@@ -197,7 +197,7 @@ public class RemoveEntriesForMissingFiles {
       return checkTable(context, RootTable.NAME, TabletsSection.getRange(), fix);
     } else {
       TableId tableId = Tables.getTableId(context, tableName);
-      Range range = new KeyExtent(tableId, null, null).toMetadataRange();
+      Range range = new KeyExtent(tableId, null, null).toMetaRange();
       return checkTable(context, MetadataTable.NAME, range, fix);
     }
   }
diff --git a/server/base/src/main/java/org/apache/accumulo/server/util/ReplicationTableUtil.java b/server/base/src/main/java/org/apache/accumulo/server/util/ReplicationTableUtil.java
index ac4b028..efeb26a 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/util/ReplicationTableUtil.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/util/ReplicationTableUtil.java
@@ -189,7 +189,7 @@ public class ReplicationTableUtil {
 
   private static Mutation createUpdateMutation(Text row, Value v, KeyExtent extent) {
     Mutation m = new Mutation(row);
-    m.put(ReplicationSection.COLF, new Text(extent.getTableId().canonical()), v);
+    m.put(ReplicationSection.COLF, new Text(extent.tableId().canonical()), v);
     return m;
   }
 }
diff --git a/server/base/src/main/java/org/apache/accumulo/server/util/TableDiskUsage.java b/server/base/src/main/java/org/apache/accumulo/server/util/TableDiskUsage.java
index dc21789..398687b 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/util/TableDiskUsage.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/util/TableDiskUsage.java
@@ -176,7 +176,7 @@ public class TableDiskUsage {
         throw new RuntimeException(e);
       }
       mdScanner.fetchColumnFamily(DataFileColumnFamily.NAME);
-      mdScanner.setRange(new KeyExtent(tableId, null, null).toMetadataRange());
+      mdScanner.setRange(new KeyExtent(tableId, null, null).toMetaRange());
 
       if (!mdScanner.iterator().hasNext()) {
         emptyTableIds.add(tableId);
diff --git a/server/base/src/main/java/org/apache/accumulo/server/util/VerifyTabletAssignments.java b/server/base/src/main/java/org/apache/accumulo/server/util/VerifyTabletAssignments.java
index ce288d5..9738c9f 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/util/VerifyTabletAssignments.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/util/VerifyTabletAssignments.java
@@ -122,18 +122,13 @@ public class VerifyTabletAssignments {
 
     ExecutorService tp = Executors.newFixedThreadPool(20);
     for (final Entry<HostAndPort,List<KeyExtent>> entry : extentsPerServer.entrySet()) {
-      Runnable r = new Runnable() {
-
-        @Override
-        public void run() {
-          try {
-            checkTabletServer(context, entry, failures);
-          } catch (Exception e) {
-            log.error("Failure on tablet server '" + entry.getKey() + ".", e);
-            failures.addAll(entry.getValue());
-          }
+      Runnable r = () -> {
+        try {
+          checkTabletServer(context, entry, failures);
+        } catch (Exception e) {
+          log.error("Failure on tablet server '" + entry.getKey() + ".", e);
+          failures.addAll(entry.getValue());
         }
-
       };
 
       tp.execute(r);
@@ -150,7 +145,7 @@ public class VerifyTabletAssignments {
   private static void checkFailures(HostAndPort server, HashSet<KeyExtent> failures,
       MultiScanResult scanResult) {
     for (TKeyExtent tke : scanResult.failures.keySet()) {
-      KeyExtent ke = new KeyExtent(tke);
+      KeyExtent ke = KeyExtent.fromThrift(tke);
       System.out.println(" Tablet " + ke + " failed at " + server);
       failures.add(ke);
     }
@@ -164,11 +159,11 @@ public class VerifyTabletAssignments {
     Map<TKeyExtent,List<TRange>> batch = new TreeMap<>();
 
     for (KeyExtent keyExtent : entry.getValue()) {
-      Text row = keyExtent.getEndRow();
+      Text row = keyExtent.endRow();
       Text row2 = null;
 
       if (row == null) {
-        row = keyExtent.getPrevEndRow();
+        row = keyExtent.prevEndRow();
 
         if (row != null) {
           row = new Text(row);
diff --git a/server/base/src/test/java/org/apache/accumulo/server/client/BulkImporterTest.java b/server/base/src/test/java/org/apache/accumulo/server/client/BulkImporterTest.java
index 98debc1..18b4fb5 100644
--- a/server/base/src/test/java/org/apache/accumulo/server/client/BulkImporterTest.java
+++ b/server/base/src/test/java/org/apache/accumulo/server/client/BulkImporterTest.java
@@ -59,9 +59,9 @@ public class BulkImporterTest {
     fakeMetaData.add(new KeyExtent(tableId, new Text("a"), null));
     for (String part : new String[] {"b", "bm", "c", "cm", "d", "dm", "e", "em", "f", "g", "h", "i",
         "j", "k", "l"}) {
-      fakeMetaData.add(new KeyExtent(tableId, new Text(part), fakeMetaData.last().getEndRow()));
+      fakeMetaData.add(new KeyExtent(tableId, new Text(part), fakeMetaData.last().endRow()));
     }
-    fakeMetaData.add(new KeyExtent(tableId, null, fakeMetaData.last().getEndRow()));
+    fakeMetaData.add(new KeyExtent(tableId, null, fakeMetaData.last().endRow()));
   }
 
   class MockTabletLocator extends TabletLocator {
diff --git a/server/base/src/test/java/org/apache/accumulo/server/master/balancer/BaseHostRegexTableLoadBalancerTest.java b/server/base/src/test/java/org/apache/accumulo/server/master/balancer/BaseHostRegexTableLoadBalancerTest.java
index 040b0f0..21aaf9a 100644
--- a/server/base/src/test/java/org/apache/accumulo/server/master/balancer/BaseHostRegexTableLoadBalancerTest.java
+++ b/server/base/src/test/java/org/apache/accumulo/server/master/balancer/BaseHostRegexTableLoadBalancerTest.java
@@ -245,7 +245,7 @@ public abstract class BaseHostRegexTableLoadBalancerTest extends HostRegexTableL
   }
 
   protected boolean tabletInBounds(KeyExtent ke, TServerInstance tsi) {
-    String tid = ke.getTableId().canonical();
+    String tid = ke.tableId().canonical();
     String host = tsi.host();
     if (tid.equals("1")
         && (host.equals("192.168.0.1") || host.equals("192.168.0.2") || host.equals("192.168.0.3")
diff --git a/server/base/src/test/java/org/apache/accumulo/server/master/balancer/ChaoticLoadBalancerTest.java b/server/base/src/test/java/org/apache/accumulo/server/master/balancer/ChaoticLoadBalancerTest.java
index 3282f34..1141359 100644
--- a/server/base/src/test/java/org/apache/accumulo/server/master/balancer/ChaoticLoadBalancerTest.java
+++ b/server/base/src/test/java/org/apache/accumulo/server/master/balancer/ChaoticLoadBalancerTest.java
@@ -50,7 +50,7 @@ public class ChaoticLoadBalancerTest {
       TabletServerStatus result = new TabletServerStatus();
       result.tableMap = new HashMap<>();
       for (KeyExtent extent : extents) {
-        TableId table = extent.getTableId();
+        TableId table = extent.tableId();
         TableInfo info = result.tableMap.get(table.canonical());
         if (info == null)
           result.tableMap.put(table.canonical(), info = new TableInfo());
@@ -71,7 +71,7 @@ public class ChaoticLoadBalancerTest {
     public List<TabletStats> getOnlineTabletsForTable(TServerInstance tserver, TableId table) {
       List<TabletStats> result = new ArrayList<>();
       for (KeyExtent extent : servers.get(tserver).extents) {
-        if (extent.getTableId().equals(table)) {
+        if (extent.tableId().equals(table)) {
           result.add(new TabletStats(extent.toThrift(), null, null, null, 0L, 0., 0., 0));
         }
       }
diff --git a/server/base/src/test/java/org/apache/accumulo/server/master/balancer/DefaultLoadBalancerTest.java b/server/base/src/test/java/org/apache/accumulo/server/master/balancer/DefaultLoadBalancerTest.java
index bd2fdd2..03ec136 100644
--- a/server/base/src/test/java/org/apache/accumulo/server/master/balancer/DefaultLoadBalancerTest.java
+++ b/server/base/src/test/java/org/apache/accumulo/server/master/balancer/DefaultLoadBalancerTest.java
@@ -54,7 +54,7 @@ public class DefaultLoadBalancerTest {
       TabletServerStatus result = new TabletServerStatus();
       result.tableMap = new HashMap<>();
       for (KeyExtent extent : extents) {
-        TableId tableId = extent.getTableId();
+        TableId tableId = extent.tableId();
         TableInfo info = result.tableMap.get(tableId.canonical());
         if (info == null)
           result.tableMap.put(tableId.canonical(), info = new TableInfo());
@@ -76,7 +76,7 @@ public class DefaultLoadBalancerTest {
     public List<TabletStats> getOnlineTabletsForTable(TServerInstance tserver, TableId table) {
       List<TabletStats> result = new ArrayList<>();
       for (KeyExtent extent : servers.get(tserver).extents) {
-        if (extent.getTableId().equals(table)) {
+        if (extent.tableId().equals(table)) {
           result.add(new TabletStats(extent.toThrift(), null, null, null, 0L, 0., 0., 0));
         }
       }
@@ -272,7 +272,7 @@ public class DefaultLoadBalancerTest {
       for (FakeTServer server : servers.values()) {
         Map<String,Integer> counts = new HashMap<>();
         for (var extent : server.extents) {
-          String t = extent.getTableId().canonical();
+          String t = extent.tableId().canonical();
           counts.putIfAbsent(t, 0);
           counts.put(t, counts.get(t) + 1);
         }
diff --git a/server/base/src/test/java/org/apache/accumulo/server/master/balancer/GroupBalancerTest.java b/server/base/src/test/java/org/apache/accumulo/server/master/balancer/GroupBalancerTest.java
index 2ea60cd..4a1e231 100644
--- a/server/base/src/test/java/org/apache/accumulo/server/master/balancer/GroupBalancerTest.java
+++ b/server/base/src/test/java/org/apache/accumulo/server/master/balancer/GroupBalancerTest.java
@@ -52,8 +52,8 @@ public class GroupBalancerTest {
 
     @Override
     public String apply(KeyExtent input) {
-      return (input == null || input.getEndRow() == null) ? null
-          : input.getEndRow().toString().substring(0, 2);
+      return (input == null || input.endRow() == null) ? null
+          : input.endRow().toString().substring(0, 2);
     }
   };
 
diff --git a/server/base/src/test/java/org/apache/accumulo/server/master/balancer/HostRegexTableLoadBalancerReconfigurationTest.java b/server/base/src/test/java/org/apache/accumulo/server/master/balancer/HostRegexTableLoadBalancerReconfigurationTest.java
index 6ebf71d..7ae3001 100644
--- a/server/base/src/test/java/org/apache/accumulo/server/master/balancer/HostRegexTableLoadBalancerReconfigurationTest.java
+++ b/server/base/src/test/java/org/apache/accumulo/server/master/balancer/HostRegexTableLoadBalancerReconfigurationTest.java
@@ -120,7 +120,7 @@ public class HostRegexTableLoadBalancerReconfigurationTest
     List<TabletStats> tablets = new ArrayList<>();
     // Report assignment information
     for (Entry<KeyExtent,TServerInstance> e : this.assignments.entrySet()) {
-      if (e.getValue().equals(tserver) && e.getKey().getTableId().equals(tableId)) {
+      if (e.getValue().equals(tserver) && e.getKey().tableId().equals(tableId)) {
         TabletStats ts = new TabletStats();
         ts.setExtent(e.getKey().toThrift());
         tablets.add(ts);
diff --git a/server/base/src/test/java/org/apache/accumulo/server/master/balancer/TableLoadBalancerTest.java b/server/base/src/test/java/org/apache/accumulo/server/master/balancer/TableLoadBalancerTest.java
index 37e9225..fb97712 100644
--- a/server/base/src/test/java/org/apache/accumulo/server/master/balancer/TableLoadBalancerTest.java
+++ b/server/base/src/test/java/org/apache/accumulo/server/master/balancer/TableLoadBalancerTest.java
@@ -177,7 +177,7 @@ public class TableLoadBalancerTest {
       if (migration.oldServer.equals(svr)) {
         count++;
       }
-      TableId key = migration.tablet.getTableId();
+      TableId key = migration.tablet.tableId();
       movedByTable.put(key, movedByTable.get(key) + 1);
     }
     assertEquals(15, count);
diff --git a/server/base/src/test/java/org/apache/accumulo/server/master/state/MergeInfoTest.java b/server/base/src/test/java/org/apache/accumulo/server/master/state/MergeInfoTest.java
index 6e07208..574deaa 100644
--- a/server/base/src/test/java/org/apache/accumulo/server/master/state/MergeInfoTest.java
+++ b/server/base/src/test/java/org/apache/accumulo/server/master/state/MergeInfoTest.java
@@ -91,10 +91,10 @@ public class MergeInfoTest {
 
   @Test
   public void testNeedsToBeChopped_DifferentTables() {
-    expect(keyExtent.getTableId()).andReturn(TableId.of("table1"));
+    expect(keyExtent.tableId()).andReturn(TableId.of("table1"));
     replay(keyExtent);
     KeyExtent keyExtent2 = createMock(KeyExtent.class);
-    expect(keyExtent2.getTableId()).andReturn(TableId.of("table2"));
+    expect(keyExtent2.tableId()).andReturn(TableId.of("table2"));
     replay(keyExtent2);
     mi = new MergeInfo(keyExtent, MergeInfo.Operation.MERGE);
     assertFalse(mi.needsToBeChopped(keyExtent2));
@@ -102,9 +102,9 @@ public class MergeInfoTest {
 
   @Test
   public void testNeedsToBeChopped_NotDelete() {
-    expect(keyExtent.getTableId()).andReturn(TableId.of("table1"));
+    expect(keyExtent.tableId()).andReturn(TableId.of("table1"));
     KeyExtent keyExtent2 = createMock(KeyExtent.class);
-    expect(keyExtent2.getTableId()).andReturn(TableId.of("table1"));
+    expect(keyExtent2.tableId()).andReturn(TableId.of("table1"));
     replay(keyExtent2);
     expect(keyExtent.overlaps(keyExtent2)).andReturn(true);
     replay(keyExtent);
@@ -128,12 +128,12 @@ public class MergeInfoTest {
   }
 
   private void testNeedsToBeChopped_Delete(String prevEndRow, boolean expected) {
-    expect(keyExtent.getTableId()).andReturn(TableId.of("table1"));
-    expect(keyExtent.getEndRow()).andReturn(new Text("prev"));
+    expect(keyExtent.tableId()).andReturn(TableId.of("table1"));
+    expect(keyExtent.endRow()).andReturn(new Text("prev"));
     replay(keyExtent);
     KeyExtent keyExtent2 = createMock(KeyExtent.class);
-    expect(keyExtent2.getTableId()).andReturn(TableId.of("table1"));
-    expect(keyExtent2.getPrevEndRow()).andReturn(prevEndRow != null ? new Text(prevEndRow) : null);
+    expect(keyExtent2.tableId()).andReturn(TableId.of("table1"));
+    expect(keyExtent2.prevEndRow()).andReturn(prevEndRow != null ? new Text(prevEndRow) : null);
     expectLastCall().anyTimes();
     replay(keyExtent2);
     mi = new MergeInfo(keyExtent, MergeInfo.Operation.DELETE);
@@ -153,9 +153,9 @@ public class MergeInfoTest {
   public void testOverlaps_DoesNotNeedChopping() {
     KeyExtent keyExtent2 = createMock(KeyExtent.class);
     expect(keyExtent.overlaps(keyExtent2)).andReturn(false);
-    expect(keyExtent.getTableId()).andReturn(TableId.of("table1"));
+    expect(keyExtent.tableId()).andReturn(TableId.of("table1"));
     replay(keyExtent);
-    expect(keyExtent2.getTableId()).andReturn(TableId.of("table2"));
+    expect(keyExtent2.tableId()).andReturn(TableId.of("table2"));
     replay(keyExtent2);
     mi = new MergeInfo(keyExtent, MergeInfo.Operation.MERGE);
     assertFalse(mi.overlaps(keyExtent2));
@@ -165,11 +165,11 @@ public class MergeInfoTest {
   public void testOverlaps_NeedsChopping() {
     KeyExtent keyExtent2 = createMock(KeyExtent.class);
     expect(keyExtent.overlaps(keyExtent2)).andReturn(false);
-    expect(keyExtent.getTableId()).andReturn(TableId.of("table1"));
-    expect(keyExtent.getEndRow()).andReturn(new Text("prev"));
+    expect(keyExtent.tableId()).andReturn(TableId.of("table1"));
+    expect(keyExtent.endRow()).andReturn(new Text("prev"));
     replay(keyExtent);
-    expect(keyExtent2.getTableId()).andReturn(TableId.of("table1"));
-    expect(keyExtent2.getPrevEndRow()).andReturn(new Text("prev"));
+    expect(keyExtent2.tableId()).andReturn(TableId.of("table1"));
+    expect(keyExtent2.prevEndRow()).andReturn(new Text("prev"));
     expectLastCall().anyTimes();
     replay(keyExtent2);
     mi = new MergeInfo(keyExtent, MergeInfo.Operation.DELETE);
diff --git a/server/base/src/test/java/org/apache/accumulo/server/master/state/TabletLocationStateTest.java b/server/base/src/test/java/org/apache/accumulo/server/master/state/TabletLocationStateTest.java
index 381134d..9b9d148 100644
--- a/server/base/src/test/java/org/apache/accumulo/server/master/state/TabletLocationStateTest.java
+++ b/server/base/src/test/java/org/apache/accumulo/server/master/state/TabletLocationStateTest.java
@@ -84,7 +84,7 @@ public class TabletLocationStateTest {
 
   @Test(expected = TabletLocationState.BadLocationStateException.class)
   public void testConstruction_FutureAndCurrent() throws Exception {
-    expect(keyExtent.getMetadataEntry()).andReturn(new Text("entry"));
+    expect(keyExtent.toMetaRow()).andReturn(new Text("entry"));
     replay(keyExtent);
     try {
       new TabletLocationState(keyExtent, future, current, last, null, walogs, true);
diff --git a/server/base/src/test/java/org/apache/accumulo/server/util/ReplicationTableUtilTest.java b/server/base/src/test/java/org/apache/accumulo/server/util/ReplicationTableUtilTest.java
index e30eb90..f8c7702 100644
--- a/server/base/src/test/java/org/apache/accumulo/server/util/ReplicationTableUtilTest.java
+++ b/server/base/src/test/java/org/apache/accumulo/server/util/ReplicationTableUtilTest.java
@@ -128,7 +128,7 @@ public class ReplicationTableUtilTest {
     ColumnUpdate col = m.getUpdates().get(0);
 
     assertEquals(ReplicationSection.COLF, new Text(col.getColumnFamily()));
-    assertEquals(extent.getTableId().canonical(), new Text(col.getColumnQualifier()).toString());
+    assertEquals(extent.tableId().canonical(), new Text(col.getColumnQualifier()).toString());
     assertEquals(0, col.getColumnVisibility().length);
     assertArrayEquals(stat.toByteArray(), col.getValue());
   }
diff --git a/server/gc/src/test/java/org/apache/accumulo/gc/GarbageCollectWriteAheadLogsTest.java b/server/gc/src/test/java/org/apache/accumulo/gc/GarbageCollectWriteAheadLogsTest.java
index f240319..b57752a 100644
--- a/server/gc/src/test/java/org/apache/accumulo/gc/GarbageCollectWriteAheadLogsTest.java
+++ b/server/gc/src/test/java/org/apache/accumulo/gc/GarbageCollectWriteAheadLogsTest.java
@@ -60,7 +60,7 @@ public class GarbageCollectWriteAheadLogsTest {
   private final Map<TServerInstance,List<UUID>> markers2 =
       Collections.singletonMap(server2, Collections.singletonList(id));
   private final Path path = new Path("hdfs://localhost:9000/accumulo/wal/localhost+1234/" + id);
-  private final KeyExtent extent = new KeyExtent(new Text("1<"), new Text(new byte[] {0}));
+  private final KeyExtent extent = KeyExtent.fromMetaRow(new Text("1<"));
   private final Collection<Collection<String>> walogs = Collections.emptyList();
   private final TabletLocationState tabletAssignedToServer1;
   private final TabletLocationState tabletAssignedToServer2;
diff --git a/server/manager/src/main/java/org/apache/accumulo/master/Master.java b/server/manager/src/main/java/org/apache/accumulo/master/Master.java
index bf289f5..54095c2 100644
--- a/server/manager/src/main/java/org/apache/accumulo/master/Master.java
+++ b/server/manager/src/main/java/org/apache/accumulo/master/Master.java
@@ -459,7 +459,7 @@ public class Master extends AbstractServer
     ServerContext context = getContext();
     synchronized (mergeLock) {
       String path =
-          getZooKeeperRoot() + Constants.ZTABLES + "/" + info.getExtent().getTableId() + "/merge";
+          getZooKeeperRoot() + Constants.ZTABLES + "/" + info.getExtent().tableId() + "/merge";
       info.setState(state);
       if (state.equals(MergeState.NONE)) {
         context.getZooReaderWriter().recursiveDelete(path, NodeMissingPolicy.SKIP);
@@ -523,7 +523,7 @@ public class Master extends AbstractServer
 
   public void clearMigrations(TableId tableId) {
     synchronized (migrations) {
-      migrations.keySet().removeIf(extent -> extent.getTableId().equals(tableId));
+      migrations.keySet().removeIf(extent -> extent.tableId().equals(tableId));
     }
   }
 
@@ -571,7 +571,7 @@ public class Master extends AbstractServer
   }
 
   TabletGoalState getTableGoalState(KeyExtent extent) {
-    TableState tableState = getContext().getTableManager().getTableState(extent.getTableId());
+    TableState tableState = getContext().getTableManager().getTableState(extent.tableId());
     if (tableState == null) {
       return TabletGoalState.DELETED;
     }
@@ -677,7 +677,7 @@ public class Master extends AbstractServer
       TabletColumnFamily.PREV_ROW_COLUMN.fetch(scanner);
       Set<KeyExtent> found = new HashSet<>();
       for (Entry<Key,Value> entry : scanner) {
-        KeyExtent extent = new KeyExtent(entry.getKey().getRow(), entry.getValue());
+        KeyExtent extent = KeyExtent.fromMetaPrevRow(entry);
         if (migrations.containsKey(extent)) {
           found.add(extent);
         }
diff --git a/server/manager/src/main/java/org/apache/accumulo/master/MasterClientServiceHandler.java b/server/manager/src/main/java/org/apache/accumulo/master/MasterClientServiceHandler.java
index 07a6e8d..e6797eb 100644
--- a/server/manager/src/main/java/org/apache/accumulo/master/MasterClientServiceHandler.java
+++ b/server/manager/src/main/java/org/apache/accumulo/master/MasterClientServiceHandler.java
@@ -78,7 +78,6 @@ import org.apache.accumulo.core.securityImpl.thrift.TDelegationTokenConfig;
 import org.apache.accumulo.core.trace.thrift.TInfo;
 import org.apache.accumulo.core.util.ByteBufferUtil;
 import org.apache.accumulo.fate.zookeeper.ZooReaderWriter;
-import org.apache.accumulo.fate.zookeeper.ZooReaderWriter.Mutator;
 import org.apache.accumulo.master.tableOps.TraceRepo;
 import org.apache.accumulo.master.tserverOps.ShutdownTServer;
 import org.apache.accumulo.server.client.ClientServiceHandler;
@@ -126,13 +125,10 @@ public class MasterClientServiceHandler extends FateServiceHandler
     ZooReaderWriter zoo = master.getContext().getZooReaderWriter();
     byte[] fid;
     try {
-      fid = zoo.mutate(zTablePath, null, null, new Mutator() {
-        @Override
-        public byte[] mutate(byte[] currentValue) {
-          long flushID = Long.parseLong(new String(currentValue));
-          flushID++;
-          return ("" + flushID).getBytes();
-        }
+      fid = zoo.mutate(zTablePath, null, null, currentValue -> {
+        long flushID = Long.parseLong(new String(currentValue));
+        flushID++;
+        return ("" + flushID).getBytes();
       });
     } catch (NoNodeException nne) {
       throw new ThriftTableOperationException(tableId.canonical(), null, TableOperation.FLUSH,
@@ -292,14 +288,15 @@ public class MasterClientServiceHandler extends FateServiceHandler
   @Override
   public void reportSplitExtent(TInfo info, TCredentials credentials, String serverName,
       TabletSplit split) {
-    KeyExtent oldTablet = new KeyExtent(split.oldTablet);
+    KeyExtent oldTablet = KeyExtent.fromThrift(split.oldTablet);
     if (master.migrations.remove(oldTablet) != null) {
       Master.log.info("Canceled migration of {}", split.oldTablet);
     }
     for (TServerInstance instance : master.tserverSet.getCurrentServers()) {
       if (serverName.equals(instance.hostPort())) {
         master.nextEvent.event("%s reported split %s, %s", serverName,
-            new KeyExtent(split.newTablets.get(0)), new KeyExtent(split.newTablets.get(1)));
+            KeyExtent.fromThrift(split.newTablets.get(0)),
+            KeyExtent.fromThrift(split.newTablets.get(1)));
         return;
       }
     }
@@ -309,7 +306,7 @@ public class MasterClientServiceHandler extends FateServiceHandler
   @Override
   public void reportTabletStatus(TInfo info, TCredentials credentials, String serverName,
       TabletLoadState status, TKeyExtent ttablet) {
-    KeyExtent tablet = new KeyExtent(ttablet);
+    KeyExtent tablet = KeyExtent.fromThrift(ttablet);
 
     switch (status) {
       case LOAD_FAILURE:
diff --git a/server/manager/src/main/java/org/apache/accumulo/master/TabletGroupWatcher.java b/server/manager/src/main/java/org/apache/accumulo/master/TabletGroupWatcher.java
index edbc069..9ddd3db 100644
--- a/server/manager/src/main/java/org/apache/accumulo/master/TabletGroupWatcher.java
+++ b/server/manager/src/main/java/org/apache/accumulo/master/TabletGroupWatcher.java
@@ -153,7 +153,7 @@ abstract class TabletGroupWatcher extends Daemon {
         Map<TableId,MergeStats> currentMerges = new HashMap<>();
         for (MergeInfo merge : master.merges()) {
           if (merge.getExtent() != null) {
-            currentMerges.put(merge.getExtent().getTableId(), new MergeStats(merge));
+            currentMerges.put(merge.getExtent().tableId(), new MergeStats(merge));
           }
         }
 
@@ -195,7 +195,7 @@ abstract class TabletGroupWatcher extends Daemon {
           }
 
           // ignore entries for tables that do not exist in zookeeper
-          if (master.getTableManager().getTableState(tls.extent.getTableId()) == null)
+          if (master.getTableManager().getTableState(tls.extent.tableId()) == null)
             continue;
 
           // Don't overwhelm the tablet servers with work
@@ -211,7 +211,7 @@ abstract class TabletGroupWatcher extends Daemon {
             unloaded = 0;
             eventListener.waitForEvents(Master.TIME_TO_WAIT_BETWEEN_SCANS);
           }
-          TableId tableId = tls.extent.getTableId();
+          TableId tableId = tls.extent.tableId();
           TableConfiguration tableConf = this.master.getContext().getTableConfiguration(tableId);
 
           MergeStats mergeStats = mergeStatsCache.get(tableId);
@@ -402,7 +402,7 @@ abstract class TabletGroupWatcher extends Daemon {
 
   private void cancelOfflineTableMigrations(TabletLocationState tls) {
     TServerInstance dest = this.master.migrations.get(tls.extent);
-    TableState tableState = master.getTableManager().getTableState(tls.extent.getTableId());
+    TableState tableState = master.getTableManager().getTableState(tls.extent.tableId());
     if (dest != null && tableState == TableState.OFFLINE) {
       this.master.migrations.remove(tls.extent);
     }
@@ -416,7 +416,7 @@ abstract class TabletGroupWatcher extends Daemon {
     try {
       Map<Key,Value> future = new HashMap<>();
       Map<Key,Value> assigned = new HashMap<>();
-      KeyExtent extent = new KeyExtent(row, new Value(new byte[] {0}));
+      KeyExtent extent = KeyExtent.fromMetaRow(row);
       String table = MetadataTable.NAME;
       if (extent.isMeta())
         table = RootTable.NAME;
@@ -487,14 +487,14 @@ abstract class TabletGroupWatcher extends Daemon {
     // Does this extent cover the end points of the delete?
     KeyExtent range = info.getExtent();
     if (tls.extent.overlaps(range)) {
-      for (Text splitPoint : new Text[] {range.getPrevEndRow(), range.getEndRow()}) {
+      for (Text splitPoint : new Text[] {range.prevEndRow(), range.endRow()}) {
         if (splitPoint == null)
           continue;
         if (!tls.extent.contains(splitPoint))
           continue;
-        if (splitPoint.equals(tls.extent.getEndRow()))
+        if (splitPoint.equals(tls.extent.endRow()))
           continue;
-        if (splitPoint.equals(tls.extent.getPrevEndRow()))
+        if (splitPoint.equals(tls.extent.prevEndRow()))
           continue;
         try {
           TServerConnection conn;
@@ -581,21 +581,21 @@ abstract class TabletGroupWatcher extends Daemon {
     Master.log.debug("Deleting tablets for {}", extent);
     MetadataTime metadataTime = null;
     KeyExtent followingTablet = null;
-    if (extent.getEndRow() != null) {
-      Key nextExtent = new Key(extent.getEndRow()).followingKey(PartialKey.ROW);
-      followingTablet = getHighTablet(
-          new KeyExtent(extent.getTableId(), nextExtent.getRow(), extent.getEndRow()));
+    if (extent.endRow() != null) {
+      Key nextExtent = new Key(extent.endRow()).followingKey(PartialKey.ROW);
+      followingTablet =
+          getHighTablet(new KeyExtent(extent.tableId(), nextExtent.getRow(), extent.endRow()));
       Master.log.debug("Found following tablet {}", followingTablet);
     }
     try {
       AccumuloClient client = this.master.getContext();
-      Text start = extent.getPrevEndRow();
+      Text start = extent.prevEndRow();
       if (start == null) {
         start = new Text();
       }
       Master.log.debug("Making file deletion entries for {}", extent);
-      Range deleteRange = new Range(TabletsSection.getRow(extent.getTableId(), start), false,
-          TabletsSection.getRow(extent.getTableId(), extent.getEndRow()), true);
+      Range deleteRange = new Range(TabletsSection.encodeRow(extent.tableId(), start), false,
+          TabletsSection.encodeRow(extent.tableId(), extent.endRow()), true);
       Scanner scanner = client.createScanner(targetSystemTable, Authorizations.EMPTY);
       scanner.setRange(deleteRange);
       ServerColumnFamily.DIRECTORY_COLUMN.fetch(scanner);
@@ -617,7 +617,7 @@ abstract class TabletGroupWatcher extends Daemon {
           throw new IllegalStateException(
               "Tablet " + key.getRow() + " is assigned during a merge!");
         } else if (ServerColumnFamily.DIRECTORY_COLUMN.hasColumns(key)) {
-          String path = GcVolumeUtil.getDeleteTabletOnAllVolumesUri(extent.getTableId(),
+          String path = GcVolumeUtil.getDeleteTabletOnAllVolumesUri(extent.tableId(),
               entry.getValue().toString());
           datafiles.add(path);
           if (datafiles.size() > 1000) {
@@ -635,12 +635,12 @@ abstract class TabletGroupWatcher extends Daemon {
       }
 
       if (followingTablet != null) {
-        Master.log.debug("Updating prevRow of {} to {}", followingTablet, extent.getPrevEndRow());
+        Master.log.debug("Updating prevRow of {} to {}", followingTablet, extent.prevEndRow());
         bw = client.createBatchWriter(targetSystemTable, new BatchWriterConfig());
         try {
-          Mutation m = new Mutation(followingTablet.getMetadataEntry());
+          Mutation m = new Mutation(followingTablet.toMetaRow());
           TabletColumnFamily.PREV_ROW_COLUMN.put(m,
-              KeyExtent.encodePrevEndRow(extent.getPrevEndRow()));
+              TabletColumnFamily.encodePrevEndRow(extent.prevEndRow()));
           ChoppedColumnFamily.CHOPPED_COLUMN.putDelete(m);
           bw.addMutation(m);
           bw.flush();
@@ -649,8 +649,7 @@ abstract class TabletGroupWatcher extends Daemon {
         }
       } else {
         // Recreate the default tablet to hold the end of the table
-        MetadataTableUtil.addTablet(
-            new KeyExtent(extent.getTableId(), null, extent.getPrevEndRow()),
+        MetadataTableUtil.addTablet(new KeyExtent(extent.tableId(), null, extent.prevEndRow()),
             ServerColumnFamily.DEFAULT_TABLET_DIR_NAME, master.getContext(), metadataTime.getType(),
             this.master.masterLock);
       }
@@ -665,13 +664,13 @@ abstract class TabletGroupWatcher extends Daemon {
     KeyExtent stop = getHighTablet(range);
     Master.log.debug("Highest tablet is {}", stop);
     Value firstPrevRowValue = null;
-    Text stopRow = stop.getMetadataEntry();
-    Text start = range.getPrevEndRow();
+    Text stopRow = stop.toMetaRow();
+    Text start = range.prevEndRow();
     if (start == null) {
       start = new Text();
     }
     Range scanRange =
-        new Range(TabletsSection.getRow(range.getTableId(), start), false, stopRow, false);
+        new Range(TabletsSection.encodeRow(range.tableId(), start), false, stopRow, false);
     String targetSystemTable = MetadataTable.NAME;
     if (range.isMeta()) {
       targetSystemTable = RootTable.NAME;
@@ -705,7 +704,7 @@ abstract class TabletGroupWatcher extends Daemon {
               TabletTime.maxMetadataTime(maxLogicalTime, MetadataTime.parse(value.toString()));
         } else if (ServerColumnFamily.DIRECTORY_COLUMN.hasColumns(key)) {
           String uri =
-              GcVolumeUtil.getDeleteTabletOnAllVolumesUri(range.getTableId(), value.toString());
+              GcVolumeUtil.getDeleteTabletOnAllVolumesUri(range.tableId(), value.toString());
           bw.addMutation(ServerAmpleImpl.createDeleteMutation(uri));
         }
       }
@@ -738,8 +737,9 @@ abstract class TabletGroupWatcher extends Daemon {
         return;
       }
 
-      stop.setPrevEndRow(KeyExtent.decodePrevEndRow(firstPrevRowValue));
-      Mutation updatePrevRow = stop.getPrevRowUpdateMutation();
+      stop = new KeyExtent(stop.tableId(), stop.endRow(),
+          TabletColumnFamily.decodePrevEndRow(firstPrevRowValue));
+      Mutation updatePrevRow = TabletColumnFamily.createPrevRowMutation(stop);
       Master.log.debug("Setting the prevRow for last tablet: {}", stop);
       bw.addMutation(updatePrevRow);
       bw.flush();
@@ -795,16 +795,15 @@ abstract class TabletGroupWatcher extends Daemon {
       Scanner scanner = client.createScanner(range.isMeta() ? RootTable.NAME : MetadataTable.NAME,
           Authorizations.EMPTY);
       TabletColumnFamily.PREV_ROW_COLUMN.fetch(scanner);
-      KeyExtent start = new KeyExtent(range.getTableId(), range.getEndRow(), null);
-      scanner.setRange(new Range(start.getMetadataEntry(), null));
+      KeyExtent start = new KeyExtent(range.tableId(), range.endRow(), null);
+      scanner.setRange(new Range(start.toMetaRow(), null));
       Iterator<Entry<Key,Value>> iterator = scanner.iterator();
       if (!iterator.hasNext()) {
         throw new AccumuloException("No last tablet for a merge " + range);
       }
       Entry<Key,Value> entry = iterator.next();
-      KeyExtent highTablet =
-          new KeyExtent(entry.getKey().getRow(), KeyExtent.decodePrevEndRow(entry.getValue()));
-      if (!highTablet.getTableId().equals(range.getTableId())) {
+      KeyExtent highTablet = KeyExtent.fromMetaPrevRow(entry);
+      if (!highTablet.tableId().equals(range.tableId())) {
         throw new AccumuloException("No last tablet for merge " + range + " " + highTablet);
       }
       return highTablet;
diff --git a/server/manager/src/main/java/org/apache/accumulo/master/state/MergeStats.java b/server/manager/src/main/java/org/apache/accumulo/master/state/MergeStats.java
index ef3680e..53810a4 100644
--- a/server/manager/src/main/java/org/apache/accumulo/master/state/MergeStats.java
+++ b/server/manager/src/main/java/org/apache/accumulo/master/state/MergeStats.java
@@ -68,9 +68,9 @@ public class MergeStats {
     this.info = info;
     if (info.getState().equals(MergeState.NONE))
       return;
-    if (info.getExtent().getEndRow() == null)
+    if (info.getExtent().endRow() == null)
       upperSplit = true;
-    if (info.getExtent().getPrevEndRow() == null)
+    if (info.getExtent().prevEndRow() == null)
       lowerSplit = true;
   }
 
@@ -81,12 +81,12 @@ public class MergeStats {
   public void update(KeyExtent ke, TabletState state, boolean chopped, boolean hasWALs) {
     if (info.getState().equals(MergeState.NONE))
       return;
-    if (!upperSplit && info.getExtent().getEndRow().equals(ke.getPrevEndRow())) {
-      log.info("Upper split found: {}", ke.getPrevEndRow());
+    if (!upperSplit && info.getExtent().endRow().equals(ke.prevEndRow())) {
+      log.info("Upper split found: {}", ke.prevEndRow());
       upperSplit = true;
     }
-    if (!lowerSplit && info.getExtent().getPrevEndRow().equals(ke.getEndRow())) {
-      log.info("Lower split found: {}", ke.getEndRow());
+    if (!lowerSplit && info.getExtent().prevEndRow().equals(ke.endRow())) {
+      log.info("Lower split found: {}", ke.endRow());
       lowerSplit = true;
     }
     if (!info.overlaps(ke))
@@ -194,12 +194,12 @@ public class MergeStats {
     Scanner scanner = accumuloClient
         .createScanner(extent.isMeta() ? RootTable.NAME : MetadataTable.NAME, Authorizations.EMPTY);
     MetaDataTableScanner.configureScanner(scanner, master);
-    Text start = extent.getPrevEndRow();
+    Text start = extent.prevEndRow();
     if (start == null) {
       start = new Text();
     }
-    TableId tableId = extent.getTableId();
-    Text first = TabletsSection.getRow(tableId, start);
+    TableId tableId = extent.tableId();
+    Text first = TabletsSection.encodeRow(tableId, start);
     Range range = new Range(first, false, null, true);
     scanner.setRange(range.clip(TabletsSection.getRange()));
     KeyExtent prevExtent = null;
@@ -214,7 +214,7 @@ public class MergeStats {
         return false;
       }
       log.debug("consistency check: {} walogs {}", tls, tls.walogs.size());
-      if (!tls.extent.getTableId().equals(tableId)) {
+      if (!tls.extent.tableId().equals(tableId)) {
         break;
       }
 
@@ -226,7 +226,7 @@ public class MergeStats {
       if (prevExtent == null) {
         // this is the first tablet observed, it must be offline and its prev row must be less than
         // the start of the merge range
-        if (tls.extent.getPrevEndRow() != null && tls.extent.getPrevEndRow().compareTo(start) > 0) {
+        if (tls.extent.prevEndRow() != null && tls.extent.prevEndRow().compareTo(start) > 0) {
           log.debug("failing consistency: prev row is too high {}", start);
           return false;
         }
@@ -247,8 +247,8 @@ public class MergeStats {
       verify.update(tls.extent, tls.getState(master.onlineTabletServers()), tls.chopped,
           !tls.walogs.isEmpty());
       // stop when we've seen the tablet just beyond our range
-      if (tls.extent.getPrevEndRow() != null && extent.getEndRow() != null
-          && tls.extent.getPrevEndRow().compareTo(extent.getEndRow()) > 0) {
+      if (tls.extent.prevEndRow() != null && extent.endRow() != null
+          && tls.extent.prevEndRow().compareTo(extent.endRow()) > 0) {
         break;
       }
     }
diff --git a/server/manager/src/main/java/org/apache/accumulo/master/tableOps/bulkVer1/CopyFailed.java b/server/manager/src/main/java/org/apache/accumulo/master/tableOps/bulkVer1/CopyFailed.java
index c7c49fa..b77aa8d 100644
--- a/server/manager/src/main/java/org/apache/accumulo/master/tableOps/bulkVer1/CopyFailed.java
+++ b/server/manager/src/main/java/org/apache/accumulo/master/tableOps/bulkVer1/CopyFailed.java
@@ -121,7 +121,7 @@ class CopyFailed extends MasterRepo {
     AccumuloClient client = master.getContext();
     try (Scanner mscanner =
         new IsolatedScanner(client.createScanner(MetadataTable.NAME, Authorizations.EMPTY))) {
-      mscanner.setRange(new KeyExtent(tableId, null, null).toMetadataRange());
+      mscanner.setRange(new KeyExtent(tableId, null, null).toMetaRange());
       mscanner.fetchColumnFamily(BulkFileColumnFamily.NAME);
 
       for (Entry<Key,Value> entry : mscanner) {
diff --git a/server/manager/src/main/java/org/apache/accumulo/master/tableOps/bulkVer2/LoadFiles.java b/server/manager/src/main/java/org/apache/accumulo/master/tableOps/bulkVer2/LoadFiles.java
index 897c41e..817497f 100644
--- a/server/manager/src/main/java/org/apache/accumulo/master/tableOps/bulkVer2/LoadFiles.java
+++ b/server/manager/src/main/java/org/apache/accumulo/master/tableOps/bulkVer2/LoadFiles.java
@@ -279,7 +279,7 @@ class LoadFiles extends MasterRepo {
           continue;
         }
 
-        Mutation mutation = new Mutation(tablet.getExtent().getMetadataEntry());
+        Mutation mutation = new Mutation(tablet.getExtent().toMetaRow());
 
         for (final Bulk.FileInfo fileInfo : files) {
           String fullPath = new Path(bulkDir, fileInfo.getFileName()).toString();
@@ -318,7 +318,7 @@ class LoadFiles extends MasterRepo {
     PeekingIterator<Map.Entry<KeyExtent,Bulk.Files>> lmi = new PeekingIterator<>(loadMapIter);
     Map.Entry<KeyExtent,Bulk.Files> loadMapEntry = lmi.peek();
 
-    Text startRow = loadMapEntry.getKey().getPrevEndRow();
+    Text startRow = loadMapEntry.getKey().prevEndRow();
 
     Iterator<TabletMetadata> tabletIter =
         TabletsMetadata.builder().forTable(tableId).overlapping(startRow, null).checkConsistency()
@@ -367,7 +367,7 @@ class LoadFiles extends MasterRepo {
       int cmp;
 
       // skip tablets until we find the prevEndRow of loadRange
-      while ((cmp = PREV_COMP.compare(currTablet.getPrevEndRow(), loadRange.getPrevEndRow())) < 0) {
+      while ((cmp = PREV_COMP.compare(currTablet.getPrevEndRow(), loadRange.prevEndRow())) < 0) {
         currTablet = tabletIter.next();
       }
 
@@ -380,7 +380,7 @@ class LoadFiles extends MasterRepo {
 
       // find the remaining tablets within the loadRange by
       // adding tablets to the list until the endRow matches the loadRange
-      while ((cmp = END_COMP.compare(currTablet.getEndRow(), loadRange.getEndRow())) < 0) {
+      while ((cmp = END_COMP.compare(currTablet.getEndRow(), loadRange.endRow())) < 0) {
         currTablet = tabletIter.next();
         tablets.add(currTablet);
       }
diff --git a/server/manager/src/main/java/org/apache/accumulo/master/tableOps/bulkVer2/PrepBulkImport.java b/server/manager/src/main/java/org/apache/accumulo/master/tableOps/bulkVer2/PrepBulkImport.java
index 058ad8e..37576ab 100644
--- a/server/manager/src/main/java/org/apache/accumulo/master/tableOps/bulkVer2/PrepBulkImport.java
+++ b/server/manager/src/main/java/org/apache/accumulo/master/tableOps/bulkVer2/PrepBulkImport.java
@@ -117,7 +117,7 @@ public class PrepBulkImport extends MasterRepo {
       TabletIterFactory tabletIterFactory, int maxNumTablets, long tid) throws Exception {
     var currRange = lmi.next();
 
-    Text startRow = currRange.getKey().getPrevEndRow();
+    Text startRow = currRange.getKey().prevEndRow();
 
     Iterator<KeyExtent> tabletIter = tabletIterFactory.newTabletIter(startRow);
 
@@ -126,8 +126,8 @@ public class PrepBulkImport extends MasterRepo {
     var fileCounts = new HashMap<String,Integer>();
     int count;
 
-    if (!tabletIter.hasNext() && equals(KeyExtent::getPrevEndRow, currTablet, currRange.getKey())
-        && equals(KeyExtent::getEndRow, currTablet, currRange.getKey()))
+    if (!tabletIter.hasNext() && equals(KeyExtent::prevEndRow, currTablet, currRange.getKey())
+        && equals(KeyExtent::endRow, currTablet, currRange.getKey()))
       currRange = null;
 
     while (tabletIter.hasNext()) {
@@ -139,21 +139,20 @@ public class PrepBulkImport extends MasterRepo {
         currRange = lmi.next();
       }
 
-      while (!equals(KeyExtent::getPrevEndRow, currTablet, currRange.getKey())
+      while (!equals(KeyExtent::prevEndRow, currTablet, currRange.getKey())
           && tabletIter.hasNext()) {
         currTablet = tabletIter.next();
       }
 
-      boolean matchedPrevRow = equals(KeyExtent::getPrevEndRow, currTablet, currRange.getKey());
+      boolean matchedPrevRow = equals(KeyExtent::prevEndRow, currTablet, currRange.getKey());
       count = matchedPrevRow ? 1 : 0;
 
-      while (!equals(KeyExtent::getEndRow, currTablet, currRange.getKey())
-          && tabletIter.hasNext()) {
+      while (!equals(KeyExtent::endRow, currTablet, currRange.getKey()) && tabletIter.hasNext()) {
         currTablet = tabletIter.next();
         count++;
       }
 
-      if (!matchedPrevRow || !equals(KeyExtent::getEndRow, currTablet, currRange.getKey())) {
+      if (!matchedPrevRow || !equals(KeyExtent::endRow, currTablet, currRange.getKey())) {
         break;
       }
 
diff --git a/server/manager/src/main/java/org/apache/accumulo/master/tableOps/create/PopulateMetadata.java b/server/manager/src/main/java/org/apache/accumulo/master/tableOps/create/PopulateMetadata.java
index 589fe35..1eb2356 100644
--- a/server/manager/src/main/java/org/apache/accumulo/master/tableOps/create/PopulateMetadata.java
+++ b/server/manager/src/main/java/org/apache/accumulo/master/tableOps/create/PopulateMetadata.java
@@ -32,6 +32,7 @@ import org.apache.accumulo.core.data.TableId;
 import org.apache.accumulo.core.data.Value;
 import org.apache.accumulo.core.dataImpl.KeyExtent;
 import org.apache.accumulo.core.metadata.schema.MetadataSchema.TabletsSection.ServerColumnFamily;
+import org.apache.accumulo.core.metadata.schema.MetadataSchema.TabletsSection.TabletColumnFamily;
 import org.apache.accumulo.core.metadata.schema.MetadataTime;
 import org.apache.accumulo.fate.Repo;
 import org.apache.accumulo.fate.zookeeper.ZooLock;
@@ -87,7 +88,8 @@ class PopulateMetadata extends MasterRepo {
     Text prevSplit = null;
     Value dirValue;
     for (Text split : Iterables.concat(splits, Collections.singleton(null))) {
-      Mutation mut = new KeyExtent(tableId, split, prevSplit).getPrevRowUpdateMutation();
+      Mutation mut =
+          TabletColumnFamily.createPrevRowMutation(new KeyExtent(tableId, split, prevSplit));
       dirValue = (split == null) ? new Value(ServerColumnFamily.DEFAULT_TABLET_DIR_NAME)
           : new Value(data.get(split));
       ServerColumnFamily.DIRECTORY_COLUMN.put(mut, dirValue);
diff --git a/server/manager/src/main/java/org/apache/accumulo/master/tableOps/delete/CleanUp.java b/server/manager/src/main/java/org/apache/accumulo/master/tableOps/delete/CleanUp.java
index 674c9f2..c2c7d6f 100644
--- a/server/manager/src/main/java/org/apache/accumulo/master/tableOps/delete/CleanUp.java
+++ b/server/manager/src/main/java/org/apache/accumulo/master/tableOps/delete/CleanUp.java
@@ -92,7 +92,7 @@ class CleanUp extends MasterRepo {
     }
 
     boolean done = true;
-    Range tableRange = new KeyExtent(tableId, null, null).toMetadataRange();
+    Range tableRange = new KeyExtent(tableId, null, null).toMetaRange();
     Scanner scanner = master.getContext().createScanner(MetadataTable.NAME, Authorizations.EMPTY);
     MetaDataTableScanner.configureScanner(scanner, master);
     scanner.setRange(tableRange);
diff --git a/server/manager/src/main/java/org/apache/accumulo/master/tableOps/tableExport/WriteExportFiles.java b/server/manager/src/main/java/org/apache/accumulo/master/tableOps/tableExport/WriteExportFiles.java
index 5d2160a..dcbb189 100644
--- a/server/manager/src/main/java/org/apache/accumulo/master/tableOps/tableExport/WriteExportFiles.java
+++ b/server/manager/src/main/java/org/apache/accumulo/master/tableOps/tableExport/WriteExportFiles.java
@@ -103,7 +103,7 @@ class WriteExportFiles extends MasterRepo {
     checkOffline(master.getContext());
 
     Scanner metaScanner = client.createScanner(MetadataTable.NAME, Authorizations.EMPTY);
-    metaScanner.setRange(new KeyExtent(tableInfo.tableID, null, null).toMetadataRange());
+    metaScanner.setRange(new KeyExtent(tableInfo.tableID, null, null).toMetaRange());
 
     // scan for locations
     metaScanner.fetchColumnFamily(CurrentLocationColumnFamily.NAME);
@@ -228,7 +228,7 @@ class WriteExportFiles extends MasterRepo {
     metaScanner.fetchColumnFamily(DataFileColumnFamily.NAME);
     TabletColumnFamily.PREV_ROW_COLUMN.fetch(metaScanner);
     ServerColumnFamily.TIME_COLUMN.fetch(metaScanner);
-    metaScanner.setRange(new KeyExtent(tableID, null, null).toMetadataRange());
+    metaScanner.setRange(new KeyExtent(tableID, null, null).toMetaRange());
 
     for (Entry<Key,Value> entry : metaScanner) {
       entry.getKey().write(dataOut);
diff --git a/server/manager/src/main/java/org/apache/accumulo/master/tableOps/tableImport/PopulateMetadataTable.java b/server/manager/src/main/java/org/apache/accumulo/master/tableOps/tableImport/PopulateMetadataTable.java
index a2a1c84..8f981b2 100644
--- a/server/manager/src/main/java/org/apache/accumulo/master/tableOps/tableImport/PopulateMetadataTable.java
+++ b/server/manager/src/main/java/org/apache/accumulo/master/tableOps/tableImport/PopulateMetadataTable.java
@@ -125,8 +125,8 @@ class PopulateMetadataTable extends MasterRepo {
             key.readFields(in);
             val.readFields(in);
 
-            Text endRow = new KeyExtent(key.getRow(), (Text) null).getEndRow();
-            Text metadataRow = new KeyExtent(tableInfo.tableId, endRow, null).getMetadataEntry();
+            Text endRow = KeyExtent.fromMetaRow(key.getRow()).endRow();
+            Text metadataRow = new KeyExtent(tableInfo.tableId, endRow, null).toMetaRow();
 
             Text cq;
 
diff --git a/server/manager/src/main/java/org/apache/accumulo/master/upgrade/Upgrader9to10.java b/server/manager/src/main/java/org/apache/accumulo/master/upgrade/Upgrader9to10.java
index 7e7ec29..2c7c66a 100644
--- a/server/manager/src/main/java/org/apache/accumulo/master/upgrade/Upgrader9to10.java
+++ b/server/manager/src/main/java/org/apache/accumulo/master/upgrade/Upgrader9to10.java
@@ -162,7 +162,7 @@ public class Upgrader9to10 implements Upgrader {
 
       UpgradeMutator tabletMutator = new UpgradeMutator(ctx);
 
-      tabletMutator.putPrevEndRow(RootTable.EXTENT.getPrevEndRow());
+      tabletMutator.putPrevEndRow(RootTable.EXTENT.prevEndRow());
 
       tabletMutator.putDirName(upgradeDirColumn(dir));
 
@@ -649,7 +649,7 @@ public class Upgrader9to10 implements Upgrader {
       return new Path(prefix + metadataEntry.substring(3));
     } else {
       // resolve style "/t-0003/C0004.rf"
-      TableId tableId = KeyExtent.tableOfMetadataRow(key.getRow());
+      TableId tableId = KeyExtent.fromMetaRow(key.getRow()).tableId();
       return new Path(prefix + tableId.canonical() + metadataEntry);
     }
   }
diff --git a/server/manager/src/test/java/org/apache/accumulo/master/tableOps/bulkVer2/PrepBulkImportTest.java b/server/manager/src/test/java/org/apache/accumulo/master/tableOps/bulkVer2/PrepBulkImportTest.java
index de9a404..60f6df6 100644
--- a/server/manager/src/test/java/org/apache/accumulo/master/tableOps/bulkVer2/PrepBulkImportTest.java
+++ b/server/manager/src/test/java/org/apache/accumulo/master/tableOps/bulkVer2/PrepBulkImportTest.java
@@ -145,7 +145,7 @@ public class PrepBulkImportTest {
   }
 
   static String toRangeStrings(Collection<KeyExtent> extents) {
-    return extents.stream().map(ke -> "(" + ke.getPrevEndRow() + "," + ke.getEndRow() + "]")
+    return extents.stream().map(ke -> "(" + ke.prevEndRow() + "," + ke.endRow() + "]")
         .collect(Collectors.joining(","));
   }
 
@@ -201,11 +201,11 @@ public class PrepBulkImportTest {
 
       Set<String> rows = new HashSet<>();
       for (KeyExtent ke : loadRanges) {
-        if (ke.getPrevEndRow() != null) {
-          rows.add(ke.getPrevEndRow().toString());
+        if (ke.prevEndRow() != null) {
+          rows.add(ke.prevEndRow().toString());
         }
-        if (ke.getEndRow() != null) {
-          rows.add(ke.getEndRow().toString());
+        if (ke.endRow() != null) {
+          rows.add(ke.endRow().toString());
         }
       }
 
diff --git a/server/monitor/src/main/java/org/apache/accumulo/monitor/rest/tables/TablesResource.java b/server/monitor/src/main/java/org/apache/accumulo/monitor/rest/tables/TablesResource.java
index 27511cc..73c8e64 100644
--- a/server/monitor/src/main/java/org/apache/accumulo/monitor/rest/tables/TablesResource.java
+++ b/server/monitor/src/main/java/org/apache/accumulo/monitor/rest/tables/TablesResource.java
@@ -150,8 +150,8 @@ public class TablesResource {
       String systemTableName =
           MetadataTable.ID.equals(tableId) ? RootTable.NAME : MetadataTable.NAME;
       MetaDataTableScanner scanner = new MetaDataTableScanner(monitor.getContext(),
-          new Range(TabletsSection.getRow(tableId, new Text()),
-              TabletsSection.getRow(tableId, null)),
+          new Range(TabletsSection.encodeRow(tableId, new Text()),
+              TabletsSection.encodeRow(tableId, null)),
           systemTableName);
 
       while (scanner.hasNext()) {
diff --git a/server/monitor/src/main/java/org/apache/accumulo/monitor/rest/tservers/TabletServerResource.java b/server/monitor/src/main/java/org/apache/accumulo/monitor/rest/tservers/TabletServerResource.java
index 258c5cb..dfa2b0f 100644
--- a/server/monitor/src/main/java/org/apache/accumulo/monitor/rest/tservers/TabletServerResource.java
+++ b/server/monitor/src/main/java/org/apache/accumulo/monitor/rest/tservers/TabletServerResource.java
@@ -322,11 +322,11 @@ public class TabletServerResource {
       ActionStatsUpdator.update(total.minors, info.minors);
       ActionStatsUpdator.update(total.majors, info.majors);
 
-      KeyExtent extent = new KeyExtent(info.extent);
-      TableId tableId = extent.getTableId();
+      KeyExtent extent = KeyExtent.fromThrift(info.extent);
+      TableId tableId = extent.tableId();
       MessageDigest digester = MessageDigest.getInstance(Constants.PW_HASH_ALGORITHM);
-      if (extent.getEndRow() != null && extent.getEndRow().getLength() > 0) {
-        digester.update(extent.getEndRow().getBytes(), 0, extent.getEndRow().getLength());
+      if (extent.endRow() != null && extent.endRow().getLength() > 0) {
+        digester.update(extent.endRow().getBytes(), 0, extent.endRow().getLength());
       }
       String obscuredExtent = Base64.getEncoder().encodeToString(digester.digest());
       String displayExtent = String.format("[%s]", obscuredExtent);
diff --git a/server/tserver/src/main/java/org/apache/accumulo/tserver/AssignmentHandler.java b/server/tserver/src/main/java/org/apache/accumulo/tserver/AssignmentHandler.java
index 900e596..23f651d 100644
--- a/server/tserver/src/main/java/org/apache/accumulo/tserver/AssignmentHandler.java
+++ b/server/tserver/src/main/java/org/apache/accumulo/tserver/AssignmentHandler.java
@@ -196,7 +196,7 @@ class AssignmentHandler implements Runnable {
         log.warn("{}", e.getMessage());
       }
 
-      TableId tableId = extent.getTableId();
+      TableId tableId = extent.tableId();
       ProblemReports.getInstance(server.getContext()).report(new ProblemReport(tableId, TABLET_LOAD,
           extent.getUUID().toString(), server.getClientAddressString(), e));
     } finally {
diff --git a/server/tserver/src/main/java/org/apache/accumulo/tserver/FileManager.java b/server/tserver/src/main/java/org/apache/accumulo/tserver/FileManager.java
index 831fca7..0f270a6 100644
--- a/server/tserver/src/main/java/org/apache/accumulo/tserver/FileManager.java
+++ b/server/tserver/src/main/java/org/apache/accumulo/tserver/FileManager.java
@@ -312,13 +312,13 @@ public class FileManager {
         // log.debug("Opening "+file + " path " + path);
         FileSKVIterator reader = FileOperations.getInstance().newReaderBuilder()
             .forFile(path.toString(), ns, ns.getConf(), context.getCryptoService())
-            .withTableConfiguration(context.getTableConfiguration(tablet.getTableId()))
+            .withTableConfiguration(context.getTableConfiguration(tablet.tableId()))
             .withCacheProvider(cacheProvider).withFileLenCache(fileLenCache).build();
         readersReserved.put(reader, file);
       } catch (Exception e) {
 
         ProblemReports.getInstance(context)
-            .report(new ProblemReport(tablet.getTableId(), ProblemType.FILE_READ, file, e));
+            .report(new ProblemReport(tablet.tableId(), ProblemType.FILE_READ, file, e));
 
         if (continueOnFailure) {
           // release the permit for the file that failed to open
@@ -474,7 +474,7 @@ public class FileManager {
       this.tablet = tablet;
       this.cacheProvider = cacheProvider;
 
-      continueOnFailure = context.getTableConfiguration(tablet.getTableId())
+      continueOnFailure = context.getTableConfiguration(tablet.tableId())
           .getBoolean(Property.TABLE_FAILURES_IGNORE);
 
       if (tablet.isMeta()) {
@@ -534,10 +534,10 @@ public class FileManager {
           FileDataSource fds = new FileDataSource(filename, source);
           dataSources.add(fds);
           SourceSwitchingIterator ssi = new SourceSwitchingIterator(fds);
-          iter = new ProblemReportingIterator(context, tablet.getTableId(), filename,
+          iter = new ProblemReportingIterator(context, tablet.tableId(), filename,
               continueOnFailure, ssi);
         } else {
-          iter = new ProblemReportingIterator(context, tablet.getTableId(), filename,
+          iter = new ProblemReportingIterator(context, tablet.tableId(), filename,
               continueOnFailure, source);
         }
 
diff --git a/server/tserver/src/main/java/org/apache/accumulo/tserver/TabletServer.java b/server/tserver/src/main/java/org/apache/accumulo/tserver/TabletServer.java
index 722a1f5..7087a07 100644
--- a/server/tserver/src/main/java/org/apache/accumulo/tserver/TabletServer.java
+++ b/server/tserver/src/main/java/org/apache/accumulo/tserver/TabletServer.java
@@ -1046,7 +1046,7 @@ public class TabletServer extends AbstractServer {
     final Map<String,TableInfo> tables = new HashMap<>();
 
     getOnlineTablets().forEach((ke, tablet) -> {
-      String tableId = ke.getTableId().canonical();
+      String tableId = ke.tableId().canonical();
       TableInfo table = tables.get(tableId);
       if (table == null) {
         table = new TableInfo();
@@ -1106,7 +1106,7 @@ public class TabletServer extends AbstractServer {
     }
 
     for (KeyExtent extent : offlineTabletsCopy) {
-      String tableId = extent.getTableId().canonical();
+      String tableId = extent.tableId().canonical();
       TableInfo table = tables.get(tableId);
       if (table == null) {
         table = new TableInfo();
@@ -1190,7 +1190,7 @@ public class TabletServer extends AbstractServer {
   }
 
   public TableConfiguration getTableConfiguration(KeyExtent extent) {
-    return getContext().getTableConfiguration(extent.getTableId());
+    return getContext().getTableConfiguration(extent.tableId());
   }
 
   public DfsLogger.ServerResources getServerConfig() {
diff --git a/server/tserver/src/main/java/org/apache/accumulo/tserver/TabletServerResourceManager.java b/server/tserver/src/main/java/org/apache/accumulo/tserver/TabletServerResourceManager.java
index 7b73ae4..b3fa2b8 100644
--- a/server/tserver/src/main/java/org/apache/accumulo/tserver/TabletServerResourceManager.java
+++ b/server/tserver/src/main/java/org/apache/accumulo/tserver/TabletServerResourceManager.java
@@ -885,11 +885,11 @@ public class TabletServerResourceManager {
       if (executor == null) {
         log.warn(
             "For table id {}, {} dispatched to non-existant executor {} Using default executor.",
-            tablet.getTableId(), dispatcher.getClass().getName(), prefs.getExecutorName());
+            tablet.tableId(), dispatcher.getClass().getName(), prefs.getExecutorName());
         executor = scanExecutors.get(SimpleScanDispatcher.DEFAULT_SCAN_EXECUTOR_NAME);
       } else if ("meta".equals(prefs.getExecutorName())) {
         log.warn("For table id {}, {} dispatched to meta executor. Using default executor.",
-            tablet.getTableId(), dispatcher.getClass().getName());
+            tablet.tableId(), dispatcher.getClass().getName());
         executor = scanExecutors.get(SimpleScanDispatcher.DEFAULT_SCAN_EXECUTOR_NAME);
       }
       executor.execute(task);
diff --git a/server/tserver/src/main/java/org/apache/accumulo/tserver/ThriftClientHandler.java b/server/tserver/src/main/java/org/apache/accumulo/tserver/ThriftClientHandler.java
index b600e65..1f83656 100644
--- a/server/tserver/src/main/java/org/apache/accumulo/tserver/ThriftClientHandler.java
+++ b/server/tserver/src/main/java/org/apache/accumulo/tserver/ThriftClientHandler.java
@@ -197,7 +197,7 @@ class ThriftClientHandler extends ClientServiceHandler implements TabletClientSe
             fileRefMap.put(new TabletFile(path), mapping.getValue());
           }
 
-          Tablet importTablet = server.getOnlineTablet(new KeyExtent(tke));
+          Tablet importTablet = server.getOnlineTablet(KeyExtent.fromThrift(tke));
 
           if (importTablet == null) {
             failures.add(tke);
@@ -205,8 +205,8 @@ class ThriftClientHandler extends ClientServiceHandler implements TabletClientSe
             try {
               importTablet.importMapFiles(tid, fileRefMap, setTime);
             } catch (IOException ioe) {
-              log.info("files {} not imported to {}: {}", fileMap.keySet(), new KeyExtent(tke),
-                  ioe.getMessage());
+              log.info("files {} not imported to {}: {}", fileMap.keySet(),
+                  KeyExtent.fromThrift(tke), ioe.getMessage());
               failures.add(tke);
             }
           }
@@ -239,14 +239,14 @@ class ThriftClientHandler extends ClientServiceHandler implements TabletClientSe
           newFileMap.put(new TabletFile(path), mapping.getValue());
         }
 
-        Tablet importTablet = server.getOnlineTablet(new KeyExtent(tke));
+        Tablet importTablet = server.getOnlineTablet(KeyExtent.fromThrift(tke));
 
         if (importTablet != null) {
           try {
             importTablet.importMapFiles(tid, newFileMap, setTime);
           } catch (IOException ioe) {
-            log.debug("files {} not imported to {}: {}", fileMap.keySet(), new KeyExtent(tke),
-                ioe.getMessage());
+            log.debug("files {} not imported to {}: {}", fileMap.keySet(),
+                KeyExtent.fromThrift(tke), ioe.getMessage());
           }
         }
       });
@@ -260,7 +260,7 @@ class ThriftClientHandler extends ClientServiceHandler implements TabletClientSe
       return null;
     }
 
-    return server.getContext().getTableConfiguration(extent.getTableId()).getScanDispatcher();
+    return server.getContext().getTableConfiguration(extent.tableId()).getScanDispatcher();
   }
 
   @Override
@@ -291,7 +291,7 @@ class ThriftClientHandler extends ClientServiceHandler implements TabletClientSe
           SecurityErrorCode.BAD_AUTHORIZATIONS);
     }
 
-    final KeyExtent extent = new KeyExtent(textent);
+    final KeyExtent extent = KeyExtent.fromThrift(textent);
 
     // wait for any writes that are in flight.. this done to ensure
     // consistency across client restarts... assume a client writes
@@ -439,7 +439,7 @@ class ThriftClientHandler extends ClientServiceHandler implements TabletClientSe
 
       if (log.isTraceEnabled()) {
         log.trace(String.format("ScanSess tid %s %s %,d entries in %.2f secs, nbTimes = [%s] ",
-            TServerUtils.clientAddress.get(), ss.extent.getTableId(), ss.entriesReturned,
+            TServerUtils.clientAddress.get(), ss.extent.tableId(), ss.entriesReturned,
             (t2 - ss.startTime) / 1000.0, ss.runStats.toString()));
       }
 
@@ -622,8 +622,8 @@ class ThriftClientHandler extends ClientServiceHandler implements TabletClientSe
       // if user has no permission to write to this table, add it to
       // the failures list
       boolean sameTable = us.currentTablet != null
-          && (us.currentTablet.getExtent().getTableId().equals(keyExtent.getTableId()));
-      tableId = keyExtent.getTableId();
+          && (us.currentTablet.getExtent().tableId().equals(keyExtent.tableId()));
+      tableId = keyExtent.tableId();
       if (sameTable || security.canWrite(us.getCredentials(), tableId,
           Tables.getNamespaceId(server.getContext(), tableId))) {
         long t2 = System.currentTimeMillis();
@@ -638,7 +638,7 @@ class ThriftClientHandler extends ClientServiceHandler implements TabletClientSe
           server.updateMetrics.addUnknownTabletErrors(0);
         }
       } else {
-        log.warn("Denying access to table {} for user {}", keyExtent.getTableId(), us.getUser());
+        log.warn("Denying access to table {} for user {}", keyExtent.tableId(), us.getUser());
         long t2 = System.currentTimeMillis();
         us.authTimes.addStat(t2 - t1);
         us.currentTablet = null;
@@ -676,7 +676,7 @@ class ThriftClientHandler extends ClientServiceHandler implements TabletClientSe
 
     boolean reserved = true;
     try {
-      KeyExtent keyExtent = new KeyExtent(tkeyExtent);
+      KeyExtent keyExtent = KeyExtent.fromThrift(tkeyExtent);
       setUpdateTablet(us, keyExtent);
 
       if (us.currentTablet != null) {
@@ -917,8 +917,8 @@ class ThriftClientHandler extends ClientServiceHandler implements TabletClientSe
       throw new ThriftSecurityException(credentials.getPrincipal(),
           SecurityErrorCode.PERMISSION_DENIED);
     }
-    final KeyExtent keyExtent = new KeyExtent(tkeyExtent);
-    final Tablet tablet = server.getOnlineTablet(new KeyExtent(keyExtent));
+    final KeyExtent keyExtent = KeyExtent.fromThrift(tkeyExtent);
+    final Tablet tablet = server.getOnlineTablet(KeyExtent.copyOf(keyExtent));
     if (tablet == null) {
       throw new NotServingTabletException(tkeyExtent);
     }
@@ -1210,9 +1210,8 @@ class ThriftClientHandler extends ClientServiceHandler implements TabletClientSe
           Translators.TKET, new Translator.ListTranslator<>(ServerConditionalMutation.TCMT));
 
       for (KeyExtent ke : updates.keySet()) {
-        if (!ke.getTableId().equals(tid)) {
-          throw new IllegalArgumentException(
-              "Unexpected table id " + tid + " != " + ke.getTableId());
+        if (!ke.tableId().equals(tid)) {
+          throw new IllegalArgumentException("Unexpected table id " + tid + " != " + ke.tableId());
         }
       }
 
@@ -1267,15 +1266,15 @@ class ThriftClientHandler extends ClientServiceHandler implements TabletClientSe
           SecurityErrorCode.PERMISSION_DENIED);
     }
 
-    KeyExtent keyExtent = new KeyExtent(tkeyExtent);
+    KeyExtent keyExtent = KeyExtent.fromThrift(tkeyExtent);
 
     Tablet tablet = server.getOnlineTablet(keyExtent);
     if (tablet == null) {
       throw new NotServingTabletException(tkeyExtent);
     }
 
-    if (keyExtent.getEndRow() == null
-        || !keyExtent.getEndRow().equals(ByteBufferUtil.toText(splitPoint))) {
+    if (keyExtent.endRow() == null
+        || !keyExtent.endRow().equals(ByteBufferUtil.toText(splitPoint))) {
       try {
         if (server.splitTablet(tablet, ByteBufferUtil.toBytes(splitPoint)) == null) {
           throw new NotServingTabletException(tkeyExtent);
@@ -1299,7 +1298,7 @@ class ThriftClientHandler extends ClientServiceHandler implements TabletClientSe
     KeyExtent start = new KeyExtent(text, new Text(), null);
     for (Entry<KeyExtent,Tablet> entry : server.getOnlineTablets().tailMap(start).entrySet()) {
       KeyExtent ke = entry.getKey();
-      if (ke.getTableId().compareTo(text) == 0) {
+      if (ke.tableId().compareTo(text) == 0) {
         Tablet tablet = entry.getValue();
         TabletStats stats = tablet.getTabletStats();
         stats.extent = ke.toThrift();
@@ -1378,7 +1377,7 @@ class ThriftClientHandler extends ClientServiceHandler implements TabletClientSe
       throw new RuntimeException(e);
     }
 
-    final KeyExtent extent = new KeyExtent(textent);
+    final KeyExtent extent = KeyExtent.fromThrift(textent);
 
     synchronized (server.unopenedTablets) {
       synchronized (server.openingTablets) {
@@ -1464,7 +1463,7 @@ class ThriftClientHandler extends ClientServiceHandler implements TabletClientSe
       throw new RuntimeException(e);
     }
 
-    KeyExtent extent = new KeyExtent(textent);
+    KeyExtent extent = KeyExtent.fromThrift(textent);
 
     server.resourceManager.addMigration(extent,
         new LoggingRunnable(log, new UnloadTabletHandler(server, extent, goal, requestTime)));
@@ -1518,13 +1517,13 @@ class ThriftClientHandler extends ClientServiceHandler implements TabletClientSe
       throw new RuntimeException(e);
     }
 
-    Tablet tablet = server.getOnlineTablet(new KeyExtent(textent));
+    Tablet tablet = server.getOnlineTablet(KeyExtent.fromThrift(textent));
     if (tablet != null) {
       log.info("Flushing {}", tablet.getExtent());
       try {
         tablet.flush(tablet.getFlushID());
       } catch (NoNodeException nne) {
-        log.info("Asked to flush tablet that has no flush id {} {}", new KeyExtent(textent),
+        log.info("Asked to flush tablet that has no flush id {} {}", KeyExtent.fromThrift(textent),
             nne.getMessage());
       }
     }
@@ -1584,7 +1583,7 @@ class ThriftClientHandler extends ClientServiceHandler implements TabletClientSe
       throw new RuntimeException(e);
     }
 
-    KeyExtent ke = new KeyExtent(textent);
+    KeyExtent ke = KeyExtent.fromThrift(textent);
 
     Tablet tablet = server.getOnlineTablet(ke);
     if (tablet != null) {
diff --git a/server/tserver/src/main/java/org/apache/accumulo/tserver/logger/LogFileKey.java b/server/tserver/src/main/java/org/apache/accumulo/tserver/logger/LogFileKey.java
index b48ef19..31dfce7 100644
--- a/server/tserver/src/main/java/org/apache/accumulo/tserver/logger/LogFileKey.java
+++ b/server/tserver/src/main/java/org/apache/accumulo/tserver/logger/LogFileKey.java
@@ -69,8 +69,7 @@ public class LogFileKey implements WritableComparable<LogFileKey> {
       case DEFINE_TABLET:
         seq = in.readLong();
         tabletId = in.readInt();
-        tablet = new KeyExtent();
-        tablet.readFields(in);
+        tablet = KeyExtent.readFrom(in);
         break;
       case MANY_MUTATIONS:
         seq = in.readLong();
@@ -109,7 +108,7 @@ public class LogFileKey implements WritableComparable<LogFileKey> {
       case DEFINE_TABLET:
         out.writeLong(seq);
         out.writeInt(tabletId);
-        tablet.write(out);
+        tablet.writeTo(out);
         break;
       case MANY_MUTATIONS:
         out.writeLong(seq);
diff --git a/server/tserver/src/main/java/org/apache/accumulo/tserver/replication/AccumuloReplicaSystem.java b/server/tserver/src/main/java/org/apache/accumulo/tserver/replication/AccumuloReplicaSystem.java
index a95bbed..afc90ff 100644
--- a/server/tserver/src/main/java/org/apache/accumulo/tserver/replication/AccumuloReplicaSystem.java
+++ b/server/tserver/src/main/java/org/apache/accumulo/tserver/replication/AccumuloReplicaSystem.java
@@ -606,7 +606,7 @@ public class AccumuloReplicaSystem implements ReplicaSystem {
 
       switch (key.event) {
         case DEFINE_TABLET:
-          if (target.getSourceTableId().equals(key.tablet.getTableId())) {
+          if (target.getSourceTableId().equals(key.tablet.tableId())) {
             desiredTids.add(key.tabletId);
           }
           break;
@@ -657,7 +657,7 @@ public class AccumuloReplicaSystem implements ReplicaSystem {
       switch (key.event) {
         case DEFINE_TABLET:
           // For new DEFINE_TABLETs, we also need to record the new tids we see
-          if (target.getSourceTableId().equals(key.tablet.getTableId())) {
+          if (target.getSourceTableId().equals(key.tablet.tableId())) {
             desiredTids.add(key.tabletId);
           }
           break;
diff --git a/server/tserver/src/main/java/org/apache/accumulo/tserver/session/MultiScanSession.java b/server/tserver/src/main/java/org/apache/accumulo/tserver/session/MultiScanSession.java
index bfbe356..887ce11 100644
--- a/server/tserver/src/main/java/org/apache/accumulo/tserver/session/MultiScanSession.java
+++ b/server/tserver/src/main/java/org/apache/accumulo/tserver/session/MultiScanSession.java
@@ -57,7 +57,7 @@ public class MultiScanSession extends ScanSession {
 
   @Override
   public TableId getTableId() {
-    return threadPoolExtent.getTableId();
+    return threadPoolExtent.tableId();
   }
 
   @Override
diff --git a/server/tserver/src/main/java/org/apache/accumulo/tserver/session/SessionManager.java b/server/tserver/src/main/java/org/apache/accumulo/tserver/session/SessionManager.java
index 7d337ff..6a39186 100644
--- a/server/tserver/src/main/java/org/apache/accumulo/tserver/session/SessionManager.java
+++ b/server/tserver/src/main/java/org/apache/accumulo/tserver/session/SessionManager.java
@@ -320,11 +320,11 @@ public class SessionManager {
       if (session instanceof SingleScanSession) {
         SingleScanSession ss = (SingleScanSession) session;
         nbt = ss.nextBatchTask;
-        tableID = ss.extent.getTableId();
+        tableID = ss.extent.tableId();
       } else if (session instanceof MultiScanSession) {
         MultiScanSession mss = (MultiScanSession) session;
         nbt = mss.lookupTask;
-        tableID = mss.threadPoolExtent.getTableId();
+        tableID = mss.threadPoolExtent.tableId();
       }
 
       if (nbt == null)
@@ -389,7 +389,7 @@ public class SessionManager {
 
         var params = ss.scanParams;
         ActiveScan activeScan =
-            new ActiveScan(ss.client, ss.getUser(), ss.extent.getTableId().canonical(),
+            new ActiveScan(ss.client, ss.getUser(), ss.extent.tableId().canonical(),
                 ct - ss.startTime, ct - ss.lastAccessTime, ScanType.SINGLE, state,
                 ss.extent.toThrift(), Translator.translate(params.getColumnSet(), Translators.CT),
                 params.getSsiList(), params.getSsio(),
@@ -425,8 +425,8 @@ public class SessionManager {
 
         var params = mss.scanParams;
         activeScans.add(new ActiveScan(mss.client, mss.getUser(),
-            mss.threadPoolExtent.getTableId().canonical(), ct - mss.startTime,
-            ct - mss.lastAccessTime, ScanType.BATCH, state, mss.threadPoolExtent.toThrift(),
+            mss.threadPoolExtent.tableId().canonical(), ct - mss.startTime, ct - mss.lastAccessTime,
+            ScanType.BATCH, state, mss.threadPoolExtent.toThrift(),
             Translator.translate(params.getColumnSet(), Translators.CT), params.getSsiList(),
             params.getSsio(), params.getAuthorizations().getAuthorizationsBB(),
             params.getClassLoaderContext()));
diff --git a/server/tserver/src/main/java/org/apache/accumulo/tserver/session/SingleScanSession.java b/server/tserver/src/main/java/org/apache/accumulo/tserver/session/SingleScanSession.java
index 4fe1829..9b8f5f0 100644
--- a/server/tserver/src/main/java/org/apache/accumulo/tserver/session/SingleScanSession.java
+++ b/server/tserver/src/main/java/org/apache/accumulo/tserver/session/SingleScanSession.java
@@ -52,7 +52,7 @@ public class SingleScanSession extends ScanSession {
 
   @Override
   public TableId getTableId() {
-    return extent.getTableId();
+    return extent.tableId();
   }
 
   @Override
diff --git a/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/CompactableImpl.java b/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/CompactableImpl.java
index 8a9c8e1..a14262a 100644
--- a/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/CompactableImpl.java
+++ b/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/CompactableImpl.java
@@ -392,7 +392,7 @@ public class CompactableImpl implements Compactable {
 
   @Override
   public TableId getTableId() {
-    return getExtent().getTableId();
+    return getExtent().tableId();
   }
 
   @Override
diff --git a/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/CompactableUtils.java b/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/CompactableUtils.java
index 2635dda..7c063ae 100644
--- a/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/CompactableUtils.java
+++ b/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/CompactableUtils.java
@@ -237,7 +237,7 @@ public class CompactableUtils {
 
       @Override
       public TableId getTableId() {
-        return tablet.getExtent().getTableId();
+        return tablet.getExtent().tableId();
       }
     });
 
@@ -254,7 +254,7 @@ public class CompactableUtils {
 
       @Override
       public TableId getTableId() {
-        return tablet.getExtent().getTableId();
+        return tablet.getExtent().tableId();
       }
     });
 
@@ -296,7 +296,7 @@ public class CompactableUtils {
 
       @Override
       public TableId getTableId() {
-        return tablet.getExtent().getTableId();
+        return tablet.getExtent().tableId();
       }
     });
 
@@ -338,7 +338,7 @@ public class CompactableUtils {
 
       @Override
       public TableId getTableId() {
-        return tablet.getExtent().getTableId();
+        return tablet.getExtent().tableId();
       }
 
       @Override
@@ -491,11 +491,11 @@ public class CompactableUtils {
         var stratClassName = tconf.get(Property.TABLE_COMPACTION_STRATEGY);
 
         try {
-          strategyWarningsCache.get(tablet.getExtent().getTableId(), () -> {
+          strategyWarningsCache.get(tablet.getExtent().tableId(), () -> {
             log.warn(
                 "Table id {} set {} to {}.  Compaction strategies are deprecated.  See the Javadoc"
                     + " for class {} for more details.",
-                tablet.getExtent().getTableId(), Property.TABLE_COMPACTION_STRATEGY.getKey(),
+                tablet.getExtent().tableId(), Property.TABLE_COMPACTION_STRATEGY.getKey(),
                 stratClassName, CompactionStrategyConfig.class.getName());
             return true;
           });
diff --git a/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/Compactor.java b/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/Compactor.java
index d5aaef0..0f891b7 100644
--- a/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/Compactor.java
+++ b/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/Compactor.java
@@ -301,7 +301,7 @@ public class Compactor implements Callable<CompactionStats> {
         readers.add(reader);
 
         SortedKeyValueIterator<Key,Value> iter = new ProblemReportingIterator(context,
-            extent.getTableId(), mapFile.getPathStr(), false, reader);
+            extent.tableId(), mapFile.getPathStr(), false, reader);
 
         if (filesToCompact.get(mapFile).isTimeSet()) {
           iter = new TimeSettingIterator(iter, filesToCompact.get(mapFile).getTime());
@@ -312,7 +312,7 @@ public class Compactor implements Callable<CompactionStats> {
       } catch (Throwable e) {
 
         ProblemReports.getInstance(context).report(
-            new ProblemReport(extent.getTableId(), ProblemType.FILE_READ, mapFile.getPathStr(), e));
+            new ProblemReport(extent.tableId(), ProblemType.FILE_READ, mapFile.getPathStr(), e));
 
         log.warn("Some problem opening map file {} {}", mapFile, e.getMessage(), e);
         // failed to open some map file... close the ones that were opened
@@ -358,10 +358,10 @@ public class Compactor implements Callable<CompactionStats> {
       TabletIteratorEnvironment iterEnv;
       if (env.getIteratorScope() == IteratorScope.majc)
         iterEnv = new TabletIteratorEnvironment(context, IteratorScope.majc, !propogateDeletes,
-            acuTableConf, getExtent().getTableId(), getMajorCompactionReason());
+            acuTableConf, getExtent().tableId(), getMajorCompactionReason());
       else if (env.getIteratorScope() == IteratorScope.minc)
         iterEnv = new TabletIteratorEnvironment(context, IteratorScope.minc, acuTableConf,
-            getExtent().getTableId());
+            getExtent().tableId());
       else
         throw new IllegalArgumentException();
 
diff --git a/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/DatafileManager.java b/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/DatafileManager.java
index 3937d1e..793cfe7 100644
--- a/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/DatafileManager.java
+++ b/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/DatafileManager.java
@@ -206,7 +206,7 @@ class DatafileManager {
       boolean inTheRightDirectory = false;
       Path parent = tpath.getPath().getParent().getParent();
       for (String tablesDir : ServerConstants.getTablesDirs(tablet.getContext())) {
-        if (parent.equals(new Path(tablesDir, tablet.getExtent().getTableId().canonical()))) {
+        if (parent.equals(new Path(tablesDir, tablet.getExtent().tableId().canonical()))) {
           inTheRightDirectory = true;
           break;
         }
diff --git a/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/MinorCompactor.java b/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/MinorCompactor.java
index 5ee84ab..69c7e88 100644
--- a/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/MinorCompactor.java
+++ b/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/MinorCompactor.java
@@ -83,10 +83,10 @@ public class MinorCompactor extends Compactor {
 
   private boolean isTableDeleting() {
     try {
-      return Tables.getTableState(tabletServer.getContext(), extent.getTableId())
+      return Tables.getTableState(tabletServer.getContext(), extent.tableId())
           == TableState.DELETING;
     } catch (Exception e) {
-      log.warn("Failed to determine if table " + extent.getTableId() + " was deleting ", e);
+      log.warn("Failed to determine if table " + extent.tableId() + " was deleting ", e);
       return false; // can not get positive confirmation that its deleting.
     }
   }
@@ -94,7 +94,7 @@ public class MinorCompactor extends Compactor {
   @Override
   protected Map<String,Set<ByteSequence>> getLocalityGroups(AccumuloConfiguration acuTableConf)
       throws IOException {
-    return LocalityGroupUtil.getLocalityGroupsIgnoringErrors(acuTableConf, extent.getTableId());
+    return LocalityGroupUtil.getLocalityGroupsIgnoringErrors(acuTableConf, extent.tableId());
   }
 
   @Override
@@ -119,23 +119,23 @@ public class MinorCompactor extends Compactor {
           // (int)(map.size()/((t2 - t1)/1000.0)), (t2 - t1)/1000.0, estimatedSizeInBytes()));
 
           if (reportedProblem) {
-            ProblemReports.getInstance(tabletServer.getContext()).deleteProblemReport(
-                getExtent().getTableId(), ProblemType.FILE_WRITE, outputFileName);
+            ProblemReports.getInstance(tabletServer.getContext())
+                .deleteProblemReport(getExtent().tableId(), ProblemType.FILE_WRITE, outputFileName);
           }
 
           return ret;
         } catch (IOException | UnsatisfiedLinkError e) {
           log.warn("MinC failed ({}) to create {} retrying ...", e.getMessage(), outputFileName);
-          ProblemReports.getInstance(tabletServer.getContext()).report(new ProblemReport(
-              getExtent().getTableId(), ProblemType.FILE_WRITE, outputFileName, e));
+          ProblemReports.getInstance(tabletServer.getContext()).report(
+              new ProblemReport(getExtent().tableId(), ProblemType.FILE_WRITE, outputFileName, e));
           reportedProblem = true;
         } catch (RuntimeException | NoClassDefFoundError e) {
           // if this is coming from a user iterator, it is possible that the user could change the
           // iterator config and that the
           // minor compaction would succeed
           log.warn("MinC failed ({}) to create {} retrying ...", e.getMessage(), outputFileName, e);
-          ProblemReports.getInstance(tabletServer.getContext()).report(new ProblemReport(
-              getExtent().getTableId(), ProblemType.FILE_WRITE, outputFileName, e));
+          ProblemReports.getInstance(tabletServer.getContext()).report(
+              new ProblemReport(getExtent().tableId(), ProblemType.FILE_WRITE, outputFileName, e));
           reportedProblem = true;
         } catch (CompactionCanceledException e) {
           throw new IllegalStateException(e);
diff --git a/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/ScanDataSource.java b/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/ScanDataSource.java
index ada53ae..1a9a98c 100644
--- a/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/ScanDataSource.java
+++ b/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/ScanDataSource.java
@@ -176,7 +176,7 @@ class ScanDataSource implements DataSource {
 
     TabletIteratorEnvironment iterEnv =
         new TabletIteratorEnvironment(tablet.getTabletServer().getContext(), IteratorScope.scan,
-            tablet.getTableConfiguration(), tablet.getExtent().getTableId(), fileManager, files,
+            tablet.getTableConfiguration(), tablet.getExtent().tableId(), fileManager, files,
             scanParams.getAuthorizations(), samplerConfig, new ArrayList<>());
 
     statsIterator =
diff --git a/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/Tablet.java b/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/Tablet.java
index d0f2050..8f64a10 100644
--- a/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/Tablet.java
+++ b/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/Tablet.java
@@ -253,10 +253,10 @@ public class Tablet {
 
   private String chooseTabletDir() throws IOException {
     VolumeChooserEnvironment chooserEnv =
-        new VolumeChooserEnvironmentImpl(extent.getTableId(), extent.getEndRow(), context);
+        new VolumeChooserEnvironmentImpl(extent.tableId(), extent.endRow(), context);
     String dirUri =
         tabletServer.getFileSystem().choose(chooserEnv, ServerConstants.getBaseUris(context))
-            + Constants.HDFS_TABLES_DIR + Path.SEPARATOR + extent.getTableId() + Path.SEPARATOR
+            + Constants.HDFS_TABLES_DIR + Path.SEPARATOR + extent.tableId() + Path.SEPARATOR
             + dirName;
     checkTabletDir(new Path(dirUri));
     return dirUri;
@@ -306,7 +306,7 @@ public class Tablet {
     if (tblConf == null) {
       Tables.clearCache(tabletServer.getContext());
       tblConf = tabletServer.getTableConfiguration(extent);
-      requireNonNull(tblConf, "Could not get table configuration for " + extent.getTableId());
+      requireNonNull(tblConf, "Could not get table configuration for " + extent.tableId());
     }
 
     this.tableConfiguration = tblConf;
@@ -443,7 +443,7 @@ public class Tablet {
       Collection<Volume> volumes = getTabletServer().getFileSystem().getVolumes();
       for (Volume volume : volumes) {
         String dirUri = volume.getBasePath() + Constants.HDFS_TABLES_DIR + Path.SEPARATOR
-            + extent.getTableId() + Path.SEPARATOR + dirName;
+            + extent.tableId() + Path.SEPARATOR + dirName;
 
         for (FileStatus tmp : getTabletServer().getFileSystem()
             .globStatus(new Path(dirUri, "*_tmp"))) {
@@ -976,7 +976,7 @@ public class Tablet {
   public long getFlushID() throws NoNodeException {
     try {
       String zTablePath = Constants.ZROOT + "/" + tabletServer.getInstanceID() + Constants.ZTABLES
-          + "/" + extent.getTableId() + Constants.ZTABLE_FLUSH_ID;
+          + "/" + extent.tableId() + Constants.ZTABLE_FLUSH_ID;
       String id = new String(context.getZooReaderWriter().getData(zTablePath, null), UTF_8);
       return Long.parseLong(id);
     } catch (InterruptedException | NumberFormatException e) {
@@ -992,7 +992,7 @@ public class Tablet {
 
   long getCompactionCancelID() {
     String zTablePath = Constants.ZROOT + "/" + tabletServer.getInstanceID() + Constants.ZTABLES
-        + "/" + extent.getTableId() + Constants.ZTABLE_COMPACT_CANCEL_ID;
+        + "/" + extent.tableId() + Constants.ZTABLE_COMPACT_CANCEL_ID;
     String id = new String(context.getZooCache().get(zTablePath), UTF_8);
     return Long.parseLong(id);
   }
@@ -1000,7 +1000,7 @@ public class Tablet {
   public Pair<Long,CompactionConfig> getCompactionID() throws NoNodeException {
     try {
       String zTablePath = Constants.ZROOT + "/" + tabletServer.getInstanceID() + Constants.ZTABLES
-          + "/" + extent.getTableId() + Constants.ZTABLE_COMPACT_ID;
+          + "/" + extent.tableId() + Constants.ZTABLE_COMPACT_ID;
 
       String[] tokens =
           new String(context.getZooReaderWriter().getData(zTablePath, null), UTF_8).split(",");
@@ -1016,7 +1016,7 @@ public class Tablet {
 
         var compactionConfig = UserCompactionUtils.decodeCompactionConfig(dis);
 
-        KeyExtent ke = new KeyExtent(extent.getTableId(), compactionConfig.getEndRow(),
+        KeyExtent ke = new KeyExtent(extent.tableId(), compactionConfig.getEndRow(),
             compactionConfig.getStartRow());
 
         if (ke.overlaps(extent)) {
@@ -1299,7 +1299,7 @@ public class Tablet {
         }
       }
       if (err != null) {
-        ProblemReports.getInstance(context).report(new ProblemReport(extent.getTableId(),
+        ProblemReports.getInstance(context).report(new ProblemReport(extent.tableId(),
             ProblemType.TABLET_LOAD, this.extent.toString(), err));
         log.error("Tablet closed consistency check has failed for {} giving up and closing",
             this.extent);
@@ -1407,8 +1407,8 @@ public class Tablet {
 
     try {
       // we should make .25 below configurable
-      keys = FileUtil.findMidPoint(context, chooseTabletDir(), extent.getPrevEndRow(),
-          extent.getEndRow(), files, .25);
+      keys = FileUtil.findMidPoint(context, chooseTabletDir(), extent.prevEndRow(), extent.endRow(),
+          files, .25);
     } catch (IOException e) {
       log.error("Failed to find midpoint {}", e.getMessage());
       return null;
@@ -1424,11 +1424,11 @@ public class Tablet {
     try {
 
       Text lastRow;
-      if (extent.getEndRow() == null) {
+      if (extent.endRow() == null) {
         Key lastKey = (Key) FileUtil.findLastKey(context, files);
         lastRow = lastKey.getRow();
       } else {
-        lastRow = extent.getEndRow();
+        lastRow = extent.endRow();
       }
 
       // We expect to get a midPoint for this set of files. If we don't get one, we have a problem.
@@ -1608,9 +1608,9 @@ public class Tablet {
 
   public TreeMap<KeyExtent,TabletData> split(byte[] sp) throws IOException {
 
-    if (sp != null && extent.getEndRow() != null && extent.getEndRow().equals(new Text(sp))) {
+    if (sp != null && extent.endRow() != null && extent.endRow().equals(new Text(sp))) {
       throw new IllegalArgumentException(
-          "Attempting to split on EndRow " + extent.getEndRow() + " for " + extent);
+          "Attempting to split on EndRow " + extent.endRow() + " for " + extent);
     }
 
     if (sp != null && sp.length > tableConfiguration.getAsBytes(Property.TABLE_MAX_END_ROW_SIZE)) {
@@ -1653,7 +1653,7 @@ public class Tablet {
       } else {
         Text tsp = new Text(sp);
         splitPoint = new SplitRowSpec(FileUtil.estimatePercentageLTE(context, chooseTabletDir(),
-            extent.getPrevEndRow(), extent.getEndRow(), getDatafileManager().getFiles(), tsp), tsp);
+            extent.prevEndRow(), extent.endRow(), getDatafileManager().getFiles(), tsp), tsp);
       }
 
       if (splitPoint == null || splitPoint.row == null) {
@@ -1668,8 +1668,8 @@ public class Tablet {
       Text midRow = splitPoint.row;
       double splitRatio = splitPoint.splitRatio;
 
-      KeyExtent low = new KeyExtent(extent.getTableId(), midRow, extent.getPrevEndRow());
-      KeyExtent high = new KeyExtent(extent.getTableId(), extent.getEndRow(), midRow);
+      KeyExtent low = new KeyExtent(extent.tableId(), midRow, extent.prevEndRow());
+      KeyExtent high = new KeyExtent(extent.tableId(), extent.endRow(), midRow);
 
       String lowDirectoryName = createTabletDirectoryName(context, midRow);
 
@@ -1687,7 +1687,7 @@ public class Tablet {
 
       MetadataTime time = tabletTime.getMetadataTime();
 
-      MetadataTableUtil.splitTablet(high, extent.getPrevEndRow(), splitRatio,
+      MetadataTableUtil.splitTablet(high, extent.prevEndRow(), splitRatio,
           getTabletServer().getContext(), getTabletServer().getLock());
       MasterMetadataUtil.addNewTablet(getTabletServer().getContext(), low, lowDirectoryName,
           getTabletServer().getTabletSession(), lowDatafileSizes, bulkImported, time, lastFlushID,
diff --git a/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/TabletMemory.java b/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/TabletMemory.java
index e1d369c..696689a 100644
--- a/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/TabletMemory.java
+++ b/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/TabletMemory.java
@@ -45,7 +45,7 @@ class TabletMemory implements Closeable {
     this.tablet = tablet;
     this.context = tablet.getContext();
     memTable =
-        new InMemoryMap(tablet.getTableConfiguration(), context, tablet.getExtent().getTableId());
+        new InMemoryMap(tablet.getTableConfiguration(), context, tablet.getExtent().tableId());
     commitSession = new CommitSession(tablet, nextSeq, memTable);
     nextSeq += 2;
   }
@@ -72,7 +72,7 @@ class TabletMemory implements Closeable {
 
     otherMemTable = memTable;
     memTable =
-        new InMemoryMap(tablet.getTableConfiguration(), context, tablet.getExtent().getTableId());
+        new InMemoryMap(tablet.getTableConfiguration(), context, tablet.getExtent().tableId());
 
     CommitSession oldCommitSession = commitSession;
     commitSession = new CommitSession(tablet, nextSeq, memTable);
diff --git a/server/tserver/src/test/java/org/apache/accumulo/tserver/CheckTabletMetadataTest.java b/server/tserver/src/test/java/org/apache/accumulo/tserver/CheckTabletMetadataTest.java
index e83d852..f84e291 100644
--- a/server/tserver/src/test/java/org/apache/accumulo/tserver/CheckTabletMetadataTest.java
+++ b/server/tserver/src/test/java/org/apache/accumulo/tserver/CheckTabletMetadataTest.java
@@ -92,7 +92,7 @@ public class CheckTabletMetadataTest {
     TreeMap<Key,Value> tabletMeta = new TreeMap<>();
 
     put(tabletMeta, "1<", TabletColumnFamily.PREV_ROW_COLUMN,
-        KeyExtent.encodePrevEndRow(null).get());
+        TabletColumnFamily.encodePrevEndRow(null).get());
     put(tabletMeta, "1<", ServerColumnFamily.DIRECTORY_COLUMN, "t1".getBytes());
     put(tabletMeta, "1<", ServerColumnFamily.TIME_COLUMN, "M0".getBytes());
     put(tabletMeta, "1<", FutureLocationColumnFamily.NAME, "4", "127.0.0.1:9997");
diff --git a/shell/src/main/java/org/apache/accumulo/shell/commands/GetSplitsCommand.java b/shell/src/main/java/org/apache/accumulo/shell/commands/GetSplitsCommand.java
index 9e7c576..0a40e5e 100644
--- a/shell/src/main/java/org/apache/accumulo/shell/commands/GetSplitsCommand.java
+++ b/shell/src/main/java/org/apache/accumulo/shell/commands/GetSplitsCommand.java
@@ -79,9 +79,9 @@ public class GetSplitsCommand extends Command {
         scanner.setRange(new Range(start, end));
         for (final Entry<Key,Value> next : scanner) {
           if (TabletColumnFamily.PREV_ROW_COLUMN.hasColumns(next.getKey())) {
-            KeyExtent extent = new KeyExtent(next.getKey().getRow(), next.getValue());
-            final String pr = encode(encode, extent.getPrevEndRow());
-            final String er = encode(encode, extent.getEndRow());
+            KeyExtent extent = KeyExtent.fromMetaPrevRow(next);
+            final String pr = encode(encode, extent.prevEndRow());
+            final String er = encode(encode, extent.endRow());
             final String line = String.format("%-26s (%s, %s%s", obscuredTabletName(extent),
                 pr == null ? "-inf" : pr, er == null ? "+inf" : er,
                 er == null ? ") Default Tablet " : "]");
@@ -117,8 +117,8 @@ public class GetSplitsCommand extends Command {
     } catch (NoSuchAlgorithmException e) {
       throw new RuntimeException(e);
     }
-    if (extent.getEndRow() != null && extent.getEndRow().getLength() > 0) {
-      digester.update(extent.getEndRow().getBytes(), 0, extent.getEndRow().getLength());
+    if (extent.endRow() != null && extent.endRow().getLength() > 0) {
+      digester.update(extent.endRow().getBytes(), 0, extent.endRow().getLength());
     }
     return Base64.getEncoder().encodeToString(digester.digest());
   }
diff --git a/test/src/main/java/org/apache/accumulo/test/CloneIT.java b/test/src/main/java/org/apache/accumulo/test/CloneIT.java
index ff64f90..fa85ec4 100644
--- a/test/src/main/java/org/apache/accumulo/test/CloneIT.java
+++ b/test/src/main/java/org/apache/accumulo/test/CloneIT.java
@@ -54,7 +54,7 @@ public class CloneIT extends AccumuloClusterHarness {
       client.tableOperations().create(tableName);
 
       KeyExtent ke = new KeyExtent(TableId.of("0"), null, null);
-      Mutation mut = ke.getPrevRowUpdateMutation();
+      Mutation mut = TabletColumnFamily.createPrevRowMutation(ke);
 
       ServerColumnFamily.TIME_COLUMN.put(mut, new Value("M0"));
       ServerColumnFamily.DIRECTORY_COLUMN.put(mut, new Value("/default_tablet"));
@@ -82,7 +82,7 @@ public class CloneIT extends AccumuloClusterHarness {
       client.tableOperations().create(tableName);
 
       KeyExtent ke = new KeyExtent(TableId.of("0"), null, null);
-      Mutation mut = ke.getPrevRowUpdateMutation();
+      Mutation mut = TabletColumnFamily.createPrevRowMutation(ke);
 
       ServerColumnFamily.TIME_COLUMN.put(mut, new Value("M0"));
       ServerColumnFamily.DIRECTORY_COLUMN.put(mut, new Value("/default_tablet"));
@@ -97,7 +97,7 @@ public class CloneIT extends AccumuloClusterHarness {
 
         MetadataTableUtil.initializeClone(tableName, TableId.of("0"), TableId.of("1"), client, bw2);
 
-        Mutation mut2 = new Mutation(ke.getMetadataEntry());
+        Mutation mut2 = new Mutation(ke.toMetaRow());
         mut2.putDelete(DataFileColumnFamily.NAME.toString(), filePrefix + "/default_tablet/0_0.rf");
         mut2.put(DataFileColumnFamily.NAME.toString(), filePrefix + "/default_tablet/1_0.rf",
             new DataFileValue(2, 300).encodeAsString());
@@ -118,7 +118,7 @@ public class CloneIT extends AccumuloClusterHarness {
       HashSet<String> files = new HashSet<>();
 
       try (Scanner scanner = client.createScanner(tableName, Authorizations.EMPTY)) {
-        scanner.setRange(new KeyExtent(TableId.of("1"), null, null).toMetadataRange());
+        scanner.setRange(new KeyExtent(TableId.of("1"), null, null).toMetaRange());
         for (Entry<Key,Value> entry : scanner) {
           if (entry.getKey().getColumnFamily().equals(DataFileColumnFamily.NAME))
             files.add(entry.getKey().getColumnQualifier().toString());
@@ -163,7 +163,7 @@ public class CloneIT extends AccumuloClusterHarness {
       int count = 0;
 
       try (Scanner scanner = client.createScanner(tableName, Authorizations.EMPTY)) {
-        scanner.setRange(new KeyExtent(TableId.of("1"), null, null).toMetadataRange());
+        scanner.setRange(new KeyExtent(TableId.of("1"), null, null).toMetaRange());
         for (Entry<Key,Value> entry : scanner) {
           if (entry.getKey().getColumnFamily().equals(DataFileColumnFamily.NAME)) {
             files.add(entry.getKey().getColumnQualifier().toString());
@@ -215,7 +215,7 @@ public class CloneIT extends AccumuloClusterHarness {
       int count = 0;
 
       try (Scanner scanner = client.createScanner(tableName, Authorizations.EMPTY)) {
-        scanner.setRange(new KeyExtent(TableId.of("1"), null, null).toMetadataRange());
+        scanner.setRange(new KeyExtent(TableId.of("1"), null, null).toMetaRange());
         for (Entry<Key,Value> entry : scanner) {
           if (entry.getKey().getColumnFamily().equals(DataFileColumnFamily.NAME)) {
             files.add(entry.getKey().getColumnQualifier().toString());
@@ -232,7 +232,7 @@ public class CloneIT extends AccumuloClusterHarness {
   private static Mutation deleteTablet(String tid, String endRow, String prevRow, String file) {
     KeyExtent ke = new KeyExtent(TableId.of(tid), endRow == null ? null : new Text(endRow),
         prevRow == null ? null : new Text(prevRow));
-    Mutation mut = new Mutation(ke.getMetadataEntry());
+    Mutation mut = new Mutation(ke.toMetaRow());
     TabletColumnFamily.PREV_ROW_COLUMN.putDelete(mut);
     ServerColumnFamily.TIME_COLUMN.putDelete(mut);
     ServerColumnFamily.DIRECTORY_COLUMN.putDelete(mut);
@@ -245,7 +245,7 @@ public class CloneIT extends AccumuloClusterHarness {
       String file) {
     KeyExtent ke = new KeyExtent(TableId.of(tid), endRow == null ? null : new Text(endRow),
         prevRow == null ? null : new Text(prevRow));
-    Mutation mut = ke.getPrevRowUpdateMutation();
+    Mutation mut = TabletColumnFamily.createPrevRowMutation(ke);
 
     ServerColumnFamily.TIME_COLUMN.put(mut, new Value("M0"));
     ServerColumnFamily.DIRECTORY_COLUMN.put(mut, new Value(dir));
@@ -289,7 +289,7 @@ public class CloneIT extends AccumuloClusterHarness {
       int count = 0;
 
       try (Scanner scanner = client.createScanner(tableName, Authorizations.EMPTY)) {
-        scanner.setRange(new KeyExtent(TableId.of("1"), null, null).toMetadataRange());
+        scanner.setRange(new KeyExtent(TableId.of("1"), null, null).toMetaRange());
         for (Entry<Key,Value> entry : scanner) {
           if (entry.getKey().getColumnFamily().equals(DataFileColumnFamily.NAME)) {
             files.add(entry.getKey().getColumnQualifier().toString());
@@ -354,7 +354,7 @@ public class CloneIT extends AccumuloClusterHarness {
       int count = 0;
 
       try (Scanner scanner = client.createScanner(tableName, Authorizations.EMPTY)) {
-        scanner.setRange(new KeyExtent(TableId.of("1"), null, null).toMetadataRange());
+        scanner.setRange(new KeyExtent(TableId.of("1"), null, null).toMetaRange());
         for (Entry<Key,Value> entry : scanner) {
           if (entry.getKey().getColumnFamily().equals(DataFileColumnFamily.NAME)) {
             files.add(entry.getKey().getColumnQualifier().toString());
diff --git a/test/src/main/java/org/apache/accumulo/test/MasterRepairsDualAssignmentIT.java b/test/src/main/java/org/apache/accumulo/test/MasterRepairsDualAssignmentIT.java
index b0537a1..473295a 100644
--- a/test/src/main/java/org/apache/accumulo/test/MasterRepairsDualAssignmentIT.java
+++ b/test/src/main/java/org/apache/accumulo/test/MasterRepairsDualAssignmentIT.java
@@ -135,7 +135,7 @@ public class MasterRepairsDualAssignmentIT extends ConfigurableMacBase {
       assertNotEquals(null, moved);
       // throw a mutation in as if we were the dying tablet
       BatchWriter bw = c.createBatchWriter(MetadataTable.NAME, new BatchWriterConfig());
-      Mutation assignment = new Mutation(moved.extent.getMetadataEntry());
+      Mutation assignment = new Mutation(moved.extent.toMetaRow());
       moved.current.putLocation(assignment);
       bw.addMutation(assignment);
       bw.close();
@@ -143,7 +143,7 @@ public class MasterRepairsDualAssignmentIT extends ConfigurableMacBase {
       waitForCleanStore(store);
       // now jam up the metadata table
       bw = c.createBatchWriter(MetadataTable.NAME, new BatchWriterConfig());
-      assignment = new Mutation(new KeyExtent(MetadataTable.ID, null, null).getMetadataEntry());
+      assignment = new Mutation(new KeyExtent(MetadataTable.ID, null, null).toMetaRow());
       moved.current.putLocation(assignment);
       bw.addMutation(assignment);
       bw.close();
diff --git a/test/src/main/java/org/apache/accumulo/test/MetaConstraintRetryIT.java b/test/src/main/java/org/apache/accumulo/test/MetaConstraintRetryIT.java
index bba4511..a38f7d5 100644
--- a/test/src/main/java/org/apache/accumulo/test/MetaConstraintRetryIT.java
+++ b/test/src/main/java/org/apache/accumulo/test/MetaConstraintRetryIT.java
@@ -50,7 +50,7 @@ public class MetaConstraintRetryIT extends AccumuloClusterHarness {
       Writer w = new Writer(context, MetadataTable.ID);
       KeyExtent extent = new KeyExtent(TableId.of("5"), null, null);
 
-      Mutation m = new Mutation(extent.getMetadataEntry());
+      Mutation m = new Mutation(extent.toMetaRow());
       // unknown columns should cause constraint violation
       m.put("badcolfam", "badcolqual", "3");
 
diff --git a/test/src/main/java/org/apache/accumulo/test/MissingWalHeaderCompletesRecoveryIT.java b/test/src/main/java/org/apache/accumulo/test/MissingWalHeaderCompletesRecoveryIT.java
index 29602fe..39b7670 100644
--- a/test/src/main/java/org/apache/accumulo/test/MissingWalHeaderCompletesRecoveryIT.java
+++ b/test/src/main/java/org/apache/accumulo/test/MissingWalHeaderCompletesRecoveryIT.java
@@ -146,7 +146,7 @@ public class MissingWalHeaderCompletesRecoveryIT extends ConfigurableMacBase {
 
       log.info("{} is offline", tableName);
 
-      Text row = TabletsSection.getRow(tableId, null);
+      Text row = TabletsSection.encodeRow(tableId, null);
       Mutation m = new Mutation(row);
       m.put(logEntry.getColumnFamily(), logEntry.getColumnQualifier(), logEntry.getValue());
 
@@ -206,7 +206,7 @@ public class MissingWalHeaderCompletesRecoveryIT extends ConfigurableMacBase {
 
       log.info("{} is offline", tableName);
 
-      Text row = TabletsSection.getRow(tableId, null);
+      Text row = TabletsSection.encodeRow(tableId, null);
       Mutation m = new Mutation(row);
       m.put(logEntry.getColumnFamily(), logEntry.getColumnQualifier(), logEntry.getValue());
 
diff --git a/test/src/main/java/org/apache/accumulo/test/SplitRecoveryIT.java b/test/src/main/java/org/apache/accumulo/test/SplitRecoveryIT.java
index a2680a0..47379d0 100644
--- a/test/src/main/java/org/apache/accumulo/test/SplitRecoveryIT.java
+++ b/test/src/main/java/org/apache/accumulo/test/SplitRecoveryIT.java
@@ -95,10 +95,10 @@ public class SplitRecoveryIT extends AccumuloClusterHarness {
         TableId tableId = TableId.of(client.tableOperations().tableIdMap().get(tableName));
 
         KeyExtent extent = new KeyExtent(tableId, null, new Text("b"));
-        Mutation m = extent.getPrevRowUpdateMutation();
+        Mutation m = TabletColumnFamily.createPrevRowMutation(extent);
 
         TabletColumnFamily.SPLIT_RATIO_COLUMN.put(m, new Value(Double.toString(0.5)));
-        TabletColumnFamily.OLD_PREV_ROW_COLUMN.put(m, KeyExtent.encodePrevEndRow(null));
+        TabletColumnFamily.OLD_PREV_ROW_COLUMN.put(m, TabletColumnFamily.encodePrevEndRow(null));
         try (BatchWriter bw = client.createBatchWriter(MetadataTable.NAME)) {
           bw.addMutation(m);
 
@@ -106,11 +106,11 @@ public class SplitRecoveryIT extends AccumuloClusterHarness {
             bw.flush();
 
             try (Scanner scanner = client.createScanner(MetadataTable.NAME)) {
-              scanner.setRange(extent.toMetadataRange());
+              scanner.setRange(extent.toMetaRange());
               scanner.fetchColumnFamily(DataFileColumnFamily.NAME);
 
               KeyExtent extent2 = new KeyExtent(tableId, new Text("b"), null);
-              m = extent2.getPrevRowUpdateMutation();
+              m = TabletColumnFamily.createPrevRowMutation(extent2);
               ServerColumnFamily.DIRECTORY_COLUMN.put(m, new Value("t2"));
               ServerColumnFamily.TIME_COLUMN.put(m, new Value("M0"));
 
diff --git a/test/src/main/java/org/apache/accumulo/test/VolumeIT.java b/test/src/main/java/org/apache/accumulo/test/VolumeIT.java
index 5cc992f..859901c 100644
--- a/test/src/main/java/org/apache/accumulo/test/VolumeIT.java
+++ b/test/src/main/java/org/apache/accumulo/test/VolumeIT.java
@@ -304,7 +304,7 @@ public class VolumeIT extends ConfigurableMacBase {
     TableId tableId = TableId.of(client.tableOperations().tableIdMap().get(tableName));
     try (Scanner metaScanner = client.createScanner(MetadataTable.NAME, Authorizations.EMPTY)) {
       metaScanner.fetchColumnFamily(DataFileColumnFamily.NAME);
-      metaScanner.setRange(new KeyExtent(tableId, null, null).toMetadataRange());
+      metaScanner.setRange(new KeyExtent(tableId, null, null).toMetaRange());
 
       int[] counts = new int[paths.length];
 
diff --git a/test/src/main/java/org/apache/accumulo/test/functional/BulkFailureIT.java b/test/src/main/java/org/apache/accumulo/test/functional/BulkFailureIT.java
index 778bf93..7ace119 100644
--- a/test/src/main/java/org/apache/accumulo/test/functional/BulkFailureIT.java
+++ b/test/src/main/java/org/apache/accumulo/test/functional/BulkFailureIT.java
@@ -174,7 +174,7 @@ public class BulkFailureIT extends AccumuloClusterHarness {
           TablePermission.WRITE);
 
       BatchDeleter bd = c.createBatchDeleter(MetadataTable.NAME, Authorizations.EMPTY, 1);
-      bd.setRanges(Collections.singleton(extent.toMetadataRange()));
+      bd.setRanges(Collections.singleton(extent.toMetaRange()));
       bd.fetchColumnFamily(BulkFileColumnFamily.NAME);
       bd.delete();
 
@@ -240,7 +240,7 @@ public class BulkFailureIT extends AccumuloClusterHarness {
     HashSet<Path> files = new HashSet<>();
 
     Scanner scanner = connector.createScanner(MetadataTable.NAME, Authorizations.EMPTY);
-    scanner.setRange(extent.toMetadataRange());
+    scanner.setRange(extent.toMetaRange());
     scanner.fetchColumnFamily(fam);
 
     for (Entry<Key,Value> entry : scanner) {
@@ -299,7 +299,7 @@ public class BulkFailureIT extends AccumuloClusterHarness {
   protected static TabletClientService.Iface getClient(ClientContext context, KeyExtent extent)
       throws AccumuloException, AccumuloSecurityException, TableNotFoundException,
       TTransportException {
-    TabletLocator locator = TabletLocator.getLocator(context, extent.getTableId());
+    TabletLocator locator = TabletLocator.getLocator(context, extent.tableId());
 
     locator.invalidateCache(extent);
 
diff --git a/test/src/main/java/org/apache/accumulo/test/functional/MasterAssignmentIT.java b/test/src/main/java/org/apache/accumulo/test/functional/MasterAssignmentIT.java
index ec4b46c..225220f 100644
--- a/test/src/main/java/org/apache/accumulo/test/functional/MasterAssignmentIT.java
+++ b/test/src/main/java/org/apache/accumulo/test/functional/MasterAssignmentIT.java
@@ -90,7 +90,7 @@ public class MasterAssignmentIT extends AccumuloClusterHarness {
 
   private TabletLocationState getTabletLocationState(AccumuloClient c, String tableId) {
     try (MetaDataTableScanner s = new MetaDataTableScanner((ClientContext) c,
-        new Range(TabletsSection.getRow(TableId.of(tableId), null)), MetadataTable.NAME)) {
+        new Range(TabletsSection.encodeRow(TableId.of(tableId), null)), MetadataTable.NAME)) {
       return s.next();
     }
   }
diff --git a/test/src/main/java/org/apache/accumulo/test/functional/SplitIT.java b/test/src/main/java/org/apache/accumulo/test/functional/SplitIT.java
index 78b9e27..3de3a69 100644
--- a/test/src/main/java/org/apache/accumulo/test/functional/SplitIT.java
+++ b/test/src/main/java/org/apache/accumulo/test/functional/SplitIT.java
@@ -142,13 +142,13 @@ public class SplitIT extends AccumuloClusterHarness {
       TableId id = TableId.of(c.tableOperations().tableIdMap().get(table));
       try (Scanner s = c.createScanner(MetadataTable.NAME, Authorizations.EMPTY)) {
         KeyExtent extent = new KeyExtent(id, null, null);
-        s.setRange(extent.toMetadataRange());
+        s.setRange(extent.toMetaRange());
         TabletColumnFamily.PREV_ROW_COLUMN.fetch(s);
         int count = 0;
         int shortened = 0;
         for (Entry<Key,Value> entry : s) {
-          extent = new KeyExtent(entry.getKey().getRow(), entry.getValue());
-          if (extent.getEndRow() != null && extent.getEndRow().toString().length() < 14)
+          extent = KeyExtent.fromMetaPrevRow(entry);
+          if (extent.endRow() != null && extent.endRow().toString().length() < 14)
             shortened++;
           count++;
         }
diff --git a/test/src/main/java/org/apache/accumulo/test/functional/SplitRecoveryIT.java b/test/src/main/java/org/apache/accumulo/test/functional/SplitRecoveryIT.java
index f58148f..1b81d68 100644
--- a/test/src/main/java/org/apache/accumulo/test/functional/SplitRecoveryIT.java
+++ b/test/src/main/java/org/apache/accumulo/test/functional/SplitRecoveryIT.java
@@ -158,7 +158,7 @@ public class SplitRecoveryIT extends ConfigurableMacBase {
 
       String dirName = "dir_" + i;
       String tdir = ServerConstants.getTablesDirs(context).iterator().next() + "/"
-          + extent.getTableId() + "/" + dirName;
+          + extent.tableId() + "/" + dirName;
       MetadataTableUtil.addTablet(extent, dirName, context, TimeType.LOGICAL, zl);
       SortedMap<TabletFile,DataFileValue> mapFiles = new TreeMap<>();
       mapFiles.put(new TabletFile(new Path(tdir + "/" + RFile.EXTENSION + "_000_000")),
@@ -176,8 +176,8 @@ public class SplitRecoveryIT extends ConfigurableMacBase {
 
     KeyExtent extent = extents[extentToSplit];
 
-    KeyExtent high = new KeyExtent(extent.getTableId(), extent.getEndRow(), midRow);
-    KeyExtent low = new KeyExtent(extent.getTableId(), midRow, extent.getPrevEndRow());
+    KeyExtent high = new KeyExtent(extent.tableId(), extent.endRow(), midRow);
+    KeyExtent low = new KeyExtent(extent.tableId(), midRow, extent.prevEndRow());
 
     splitPartiallyAndRecover(context, extent, high, low, .4, splitMapFiles, midRow,
         "localhost:1234", failPoint, zl);
@@ -204,11 +204,11 @@ public class SplitRecoveryIT extends ConfigurableMacBase {
     MetadataTableUtil.splitDatafiles(midRow, splitRatio, new HashMap<>(), mapFiles,
         lowDatafileSizes, highDatafileSizes, highDatafilesToRemove);
 
-    MetadataTableUtil.splitTablet(high, extent.getPrevEndRow(), splitRatio, context, zl);
+    MetadataTableUtil.splitTablet(high, extent.prevEndRow(), splitRatio, context, zl);
     TServerInstance instance = new TServerInstance(location, zl.getSessionId());
     Writer writer = MetadataTableUtil.getMetadataTable(context);
     Assignment assignment = new Assignment(high, instance);
-    Mutation m = new Mutation(assignment.tablet.getMetadataEntry());
+    Mutation m = new Mutation(assignment.tablet.toMetaRow());
     assignment.server.putFutureLocation(m);
     writer.update(m);
 
@@ -252,7 +252,7 @@ public class SplitRecoveryIT extends ConfigurableMacBase {
   private void ensureTabletHasNoUnexpectedMetadataEntries(ServerContext context, KeyExtent extent,
       SortedMap<StoredTabletFile,DataFileValue> expectedMapFiles) throws Exception {
     try (Scanner scanner = new ScannerImpl(context, MetadataTable.ID, Authorizations.EMPTY)) {
-      scanner.setRange(extent.toMetadataRange());
+      scanner.setRange(extent.toMetaRange());
 
       HashSet<ColumnFQ> expectedColumns = new HashSet<>();
       expectedColumns.add(ServerColumnFamily.DIRECTORY_COLUMN);
@@ -275,14 +275,14 @@ public class SplitRecoveryIT extends ConfigurableMacBase {
         Entry<Key,Value> entry = iter.next();
         Key key = entry.getKey();
 
-        if (!key.getRow().equals(extent.getMetadataEntry())) {
+        if (!key.getRow().equals(extent.toMetaRow())) {
           throw new Exception(
               "Tablet " + extent + " contained unexpected " + MetadataTable.NAME + " entry " + key);
         }
 
         if (TabletColumnFamily.PREV_ROW_COLUMN.hasColumns(key)) {
           sawPer = true;
-          if (!new KeyExtent(key.getRow(), entry.getValue()).equals(extent)) {
+          if (!KeyExtent.fromMetaPrevRow(entry).equals(extent)) {
             throw new Exception("Unexpected prev end row " + entry);
           }
         }
diff --git a/test/src/main/java/org/apache/accumulo/test/functional/TableIT.java b/test/src/main/java/org/apache/accumulo/test/functional/TableIT.java
index c88d5ad..1b911c9 100644
--- a/test/src/main/java/org/apache/accumulo/test/functional/TableIT.java
+++ b/test/src/main/java/org/apache/accumulo/test/functional/TableIT.java
@@ -75,7 +75,7 @@ public class TableIT extends AccumuloClusterHarness {
       VerifyIngest.verifyIngest(c, params);
       TableId id = TableId.of(to.tableIdMap().get(tableName));
       try (Scanner s = c.createScanner(MetadataTable.NAME, Authorizations.EMPTY)) {
-        s.setRange(new KeyExtent(id, null, null).toMetadataRange());
+        s.setRange(new KeyExtent(id, null, null).toMetaRange());
         s.fetchColumnFamily(DataFileColumnFamily.NAME);
         assertTrue(Iterators.size(s.iterator()) > 0);
 
diff --git a/test/src/main/java/org/apache/accumulo/test/functional/TabletStateChangeIteratorIT.java b/test/src/main/java/org/apache/accumulo/test/functional/TabletStateChangeIteratorIT.java
index 8ac0508..27647e6 100644
--- a/test/src/main/java/org/apache/accumulo/test/functional/TabletStateChangeIteratorIT.java
+++ b/test/src/main/java/org/apache/accumulo/test/functional/TabletStateChangeIteratorIT.java
@@ -154,7 +154,7 @@ public class TabletStateChangeIteratorIT extends AccumuloClusterHarness {
       throws TableNotFoundException, MutationsRejectedException {
     TableId tableIdToModify =
         TableId.of(client.tableOperations().tableIdMap().get(tableNameToModify));
-    Mutation m = new Mutation(new KeyExtent(tableIdToModify, null, null).getMetadataEntry());
+    Mutation m = new Mutation(new KeyExtent(tableIdToModify, null, null).toMetaRow());
     m.put(CurrentLocationColumnFamily.NAME, new Text("1234567"), new Value("fake:9005"));
     try (BatchWriter bw = client.createBatchWriter(table)) {
       bw.addMutation(m);
@@ -166,7 +166,7 @@ public class TabletStateChangeIteratorIT extends AccumuloClusterHarness {
     TableId tableIdToModify =
         TableId.of(client.tableOperations().tableIdMap().get(tableNameToModify));
     try (Scanner scanner = client.createScanner(table, Authorizations.EMPTY)) {
-      scanner.setRange(new KeyExtent(tableIdToModify, null, null).toMetadataRange());
+      scanner.setRange(new KeyExtent(tableIdToModify, null, null).toMetaRange());
       scanner.fetchColumnFamily(CurrentLocationColumnFamily.NAME);
       Entry<Key,Value> entry = scanner.iterator().next();
       Mutation m = new Mutation(entry.getKey().getRow());
@@ -186,8 +186,8 @@ public class TabletStateChangeIteratorIT extends AccumuloClusterHarness {
         TableId.of(client.tableOperations().tableIdMap().get(tableNameToModify));
     BatchDeleter deleter =
         client.createBatchDeleter(table, Authorizations.EMPTY, 1, new BatchWriterConfig());
-    deleter.setRanges(
-        Collections.singleton(new KeyExtent(tableIdToModify, null, null).toMetadataRange()));
+    deleter
+        .setRanges(Collections.singleton(new KeyExtent(tableIdToModify, null, null).toMetaRange()));
     deleter.fetchColumnFamily(CurrentLocationColumnFamily.NAME);
     deleter.delete();
     deleter.close();
diff --git a/test/src/main/java/org/apache/accumulo/test/functional/WALSunnyDayIT.java b/test/src/main/java/org/apache/accumulo/test/functional/WALSunnyDayIT.java
index 2ac61bd..853e024 100644
--- a/test/src/main/java/org/apache/accumulo/test/functional/WALSunnyDayIT.java
+++ b/test/src/main/java/org/apache/accumulo/test/functional/WALSunnyDayIT.java
@@ -147,7 +147,7 @@ public class WALSunnyDayIT extends ConfigurableMacBase {
       // log.debug("markers " + markers);
       assertEquals("one tablet should have markers", 1, markers.size());
       assertEquals("tableId of the keyExtent should be 1", "1",
-          markers.keySet().iterator().next().getTableId().canonical());
+          markers.keySet().iterator().next().tableId().canonical());
 
       // put some data in the WAL
       assertEquals(0, cluster.exec(SetGoalState.class, "NORMAL").getProcess().waitFor());
@@ -216,7 +216,7 @@ public class WALSunnyDayIT extends ConfigurableMacBase {
           logs.add(key.getColumnQualifier().toString());
         }
         if (TabletColumnFamily.PREV_ROW_COLUMN.hasColumns(key) && !logs.isEmpty()) {
-          KeyExtent extent = new KeyExtent(key.getRow(), entry.getValue());
+          KeyExtent extent = KeyExtent.fromMetaPrevRow(entry);
           result.put(extent, logs);
           logs = new ArrayList<>();
         }
diff --git a/test/src/main/java/org/apache/accumulo/test/master/MergeStateIT.java b/test/src/main/java/org/apache/accumulo/test/master/MergeStateIT.java
index 0555d87..6629a5f 100644
--- a/test/src/main/java/org/apache/accumulo/test/master/MergeStateIT.java
+++ b/test/src/main/java/org/apache/accumulo/test/master/MergeStateIT.java
@@ -124,7 +124,8 @@ public class MergeStateIT extends ConfigurableMacBase {
       Text pr = null;
       for (String s : splits) {
         Text split = new Text(s);
-        Mutation prevRow = KeyExtent.getPrevRowUpdateMutation(new KeyExtent(tableId, split, pr));
+        Mutation prevRow =
+            TabletColumnFamily.createPrevRowMutation(new KeyExtent(tableId, split, pr));
         prevRow.put(CurrentLocationColumnFamily.NAME, new Text("123456"),
             new Value("127.0.0.1:1234"));
         ChoppedColumnFamily.CHOPPED_COLUMN.put(prevRow, new Value("junk"));
@@ -132,7 +133,8 @@ public class MergeStateIT extends ConfigurableMacBase {
         pr = split;
       }
       // Add the default tablet
-      Mutation defaultTablet = KeyExtent.getPrevRowUpdateMutation(new KeyExtent(tableId, null, pr));
+      Mutation defaultTablet =
+          TabletColumnFamily.createPrevRowMutation(new KeyExtent(tableId, null, pr));
       defaultTablet.put(CurrentLocationColumnFamily.NAME, new Text("123456"),
           new Value("127.0.0.1:1234"));
       bw.addMutation(defaultTablet);
@@ -155,9 +157,11 @@ public class MergeStateIT extends ConfigurableMacBase {
 
       // Create the hole
       // Split the tablet at one end of the range
-      Mutation m = new KeyExtent(tableId, new Text("t"), new Text("p")).getPrevRowUpdateMutation();
+      Mutation m = TabletColumnFamily
+          .createPrevRowMutation(new KeyExtent(tableId, new Text("t"), new Text("p")));
       TabletColumnFamily.SPLIT_RATIO_COLUMN.put(m, new Value("0.5"));
-      TabletColumnFamily.OLD_PREV_ROW_COLUMN.put(m, KeyExtent.encodePrevEndRow(new Text("o")));
+      TabletColumnFamily.OLD_PREV_ROW_COLUMN.put(m,
+          TabletColumnFamily.encodePrevEndRow(new Text("o")));
       update(accumuloClient, m);
 
       // do the state check
@@ -178,7 +182,7 @@ public class MergeStateIT extends ConfigurableMacBase {
 
       // finish the split
       KeyExtent tablet = new KeyExtent(tableId, new Text("p"), new Text("o"));
-      m = tablet.getPrevRowUpdateMutation();
+      m = TabletColumnFamily.createPrevRowMutation(tablet);
       TabletColumnFamily.SPLIT_RATIO_COLUMN.put(m, new Value("0.5"));
       update(accumuloClient, m);
       metaDataStateStore
@@ -189,7 +193,7 @@ public class MergeStateIT extends ConfigurableMacBase {
       assertEquals(MergeState.WAITING_FOR_CHOPPED, stats.nextMergeState(accumuloClient, state));
 
       // chop it
-      m = tablet.getPrevRowUpdateMutation();
+      m = TabletColumnFamily.createPrevRowMutation(tablet);
       ChoppedColumnFamily.CHOPPED_COLUMN.put(m, new Value("junk"));
       update(accumuloClient, m);
 
@@ -197,7 +201,7 @@ public class MergeStateIT extends ConfigurableMacBase {
       assertEquals(MergeState.WAITING_FOR_OFFLINE, stats.nextMergeState(accumuloClient, state));
 
       // take it offline
-      m = tablet.getPrevRowUpdateMutation();
+      m = TabletColumnFamily.createPrevRowMutation(tablet);
       Collection<Collection<String>> walogs = Collections.emptyList();
       metaDataStateStore.unassign(
           Collections.singletonList(
diff --git a/test/src/main/java/org/apache/accumulo/test/master/SuspendedTabletsIT.java b/test/src/main/java/org/apache/accumulo/test/master/SuspendedTabletsIT.java
index 223c2c1..f905436 100644
--- a/test/src/main/java/org/apache/accumulo/test/master/SuspendedTabletsIT.java
+++ b/test/src/main/java/org/apache/accumulo/test/master/SuspendedTabletsIT.java
@@ -315,7 +315,7 @@ public class SuspendedTabletsIT extends ConfigurableMacBase {
         while (scanner.hasNext()) {
           TabletLocationState tls = scanner.next();
 
-          if (!tls.extent.getTableId().canonical().equals(tableId)) {
+          if (!tls.extent.tableId().canonical().equals(tableId)) {
             continue;
           }
           locationStates.put(tls.extent, tls);
diff --git a/test/src/main/java/org/apache/accumulo/test/performance/NullTserver.java b/test/src/main/java/org/apache/accumulo/test/performance/NullTserver.java
index cd0c3c0..999ad89 100644
--- a/test/src/main/java/org/apache/accumulo/test/performance/NullTserver.java
+++ b/test/src/main/java/org/apache/accumulo/test/performance/NullTserver.java
@@ -312,7 +312,7 @@ public class NullTserver {
     TableId tableId = Tables.getTableId(context, opts.tableName);
 
     // read the locations for the table
-    Range tableRange = new KeyExtent(tableId, null, null).toMetadataRange();
+    Range tableRange = new KeyExtent(tableId, null, null).toMetaRange();
     List<Assignment> assignments = new ArrayList<>();
     try (var s = new MetaDataTableScanner(context, tableRange, MetadataTable.NAME)) {
       long randomSessionID = opts.port;
diff --git a/test/src/main/java/org/apache/accumulo/test/performance/scan/CollectTabletStats.java b/test/src/main/java/org/apache/accumulo/test/performance/scan/CollectTabletStats.java
index a3ee4f1..32c004c 100644
--- a/test/src/main/java/org/apache/accumulo/test/performance/scan/CollectTabletStats.java
+++ b/test/src/main/java/org/apache/accumulo/test/performance/scan/CollectTabletStats.java
@@ -223,8 +223,8 @@ public class CollectTabletStats {
           Test test = new Test(ke) {
             @Override
             public int runTest() throws Exception {
-              return scanTablet(client, opts.tableName, opts.auths, ke.getPrevEndRow(),
-                  ke.getEndRow(), columns);
+              return scanTablet(client, opts.tableName, opts.auths, ke.prevEndRow(), ke.endRow(),
+                  columns);
             }
           };
           tests.add(test);
@@ -464,7 +464,7 @@ public class CollectTabletStats {
       FileSKVIterator reader = FileOperations.getInstance().newReaderBuilder()
           .forFile(file.getPathStr(), ns, ns.getConf(), CryptoServiceFactory.newDefaultInstance())
           .withTableConfiguration(aconf).build();
-      Range range = new Range(ke.getPrevEndRow(), false, ke.getEndRow(), true);
+      Range range = new Range(ke.prevEndRow(), false, ke.endRow(), true);
       reader.seek(range, columnSet, !columnSet.isEmpty());
       while (reader.hasTop() && !range.afterEndKey(reader.getTopKey())) {
         count++;
@@ -501,13 +501,13 @@ public class CollectTabletStats {
 
     List<IterInfo> emptyIterinfo = Collections.emptyList();
     Map<String,Map<String,String>> emptySsio = Collections.emptyMap();
-    TableConfiguration tconf = context.getTableConfiguration(ke.getTableId());
+    TableConfiguration tconf = context.getTableConfiguration(ke.tableId());
     reader = createScanIterator(ke, readers, auths, new byte[] {}, new HashSet<>(), emptyIterinfo,
         emptySsio, useTableIterators, tconf);
 
     HashSet<ByteSequence> columnSet = createColumnBSS(columns);
 
-    reader.seek(new Range(ke.getPrevEndRow(), false, ke.getEndRow(), true), columnSet,
+    reader.seek(new Range(ke.prevEndRow(), false, ke.endRow(), true), columnSet,
         !columnSet.isEmpty());
 
     int count = 0;
@@ -547,7 +547,7 @@ public class CollectTabletStats {
     // long t1 = System.currentTimeMillis();
 
     try (Scanner scanner = client.createScanner(table, auths)) {
-      scanner.setRange(new Range(ke.getPrevEndRow(), false, ke.getEndRow(), true));
+      scanner.setRange(new Range(ke.prevEndRow(), false, ke.endRow(), true));
 
       for (String c : columns) {
         scanner.fetchColumnFamily(new Text(c));
diff --git a/test/src/main/java/org/apache/accumulo/test/replication/ReplicationIT.java b/test/src/main/java/org/apache/accumulo/test/replication/ReplicationIT.java
index 91ecb2b..b35a3d4 100644
--- a/test/src/main/java/org/apache/accumulo/test/replication/ReplicationIT.java
+++ b/test/src/main/java/org/apache/accumulo/test/replication/ReplicationIT.java
@@ -160,7 +160,7 @@ public class ReplicationIT extends ConfigurableMacBase {
       scanner.fetchColumnFamily(CurrentLocationColumnFamily.NAME);
       for (Entry<Key,Value> entry : scanner) {
         var tServer = new TServerInstance(entry.getValue(), entry.getKey().getColumnQualifier());
-        TableId tableId = KeyExtent.tableOfMetadataRow(entry.getKey().getRow());
+        TableId tableId = KeyExtent.fromMetaRow(entry.getKey().getRow()).tableId();
         serverToTableID.put(tServer, tableId);
       }
       // Map of logs to tableId
@@ -551,20 +551,16 @@ public class ReplicationIT extends ConfigurableMacBase {
       final Multimap<String,TableId> logs = HashMultimap.create();
       final AtomicBoolean keepRunning = new AtomicBoolean(true);
 
-      Thread t = new Thread(new Runnable() {
-        @Override
-        public void run() {
-          // Should really be able to interrupt here, but the Scanner throws a fit to the logger
-          // when that happens
-          while (keepRunning.get()) {
-            try {
-              logs.putAll(getAllLogs(client, context));
-            } catch (Exception e) {
-              log.error("Error getting logs", e);
-            }
+      Thread t = new Thread(() -> {
+        // Should really be able to interrupt here, but the Scanner throws a fit to the logger
+        // when that happens
+        while (keepRunning.get()) {
+          try {
+            logs.putAll(getAllLogs(client, context));
+          } catch (Exception e) {
+            log.error("Error getting logs", e);
           }
         }
-
       });
 
       t.start();
@@ -1135,20 +1131,16 @@ public class ReplicationIT extends ConfigurableMacBase {
       final AtomicBoolean keepRunning = new AtomicBoolean(true);
       final Set<String> metadataWals = new HashSet<>();
 
-      Thread t = new Thread(new Runnable() {
-        @Override
-        public void run() {
-          // Should really be able to interrupt here, but the Scanner throws a fit to the logger
-          // when that happens
-          while (keepRunning.get()) {
-            try {
-              metadataWals.addAll(getLogs(client, context).keySet());
-            } catch (Exception e) {
-              log.error("Metadata table doesn't exist");
-            }
+      Thread t = new Thread(() -> {
+        // Should really be able to interrupt here, but the Scanner throws a fit to the logger
+        // when that happens
+        while (keepRunning.get()) {
+          try {
+            metadataWals.addAll(getLogs(client, context).keySet());
+          } catch (Exception e) {
+            log.error("Metadata table doesn't exist");
           }
         }
-
       });
 
       t.start();
diff --git a/test/src/main/java/org/apache/accumulo/test/replication/UnusedWalDoesntCloseReplicationStatusIT.java b/test/src/main/java/org/apache/accumulo/test/replication/UnusedWalDoesntCloseReplicationStatusIT.java
index 7bd83ca..39c17cb 100644
--- a/test/src/main/java/org/apache/accumulo/test/replication/UnusedWalDoesntCloseReplicationStatusIT.java
+++ b/test/src/main/java/org/apache/accumulo/test/replication/UnusedWalDoesntCloseReplicationStatusIT.java
@@ -187,7 +187,7 @@ public class UnusedWalDoesntCloseReplicationStatusIT extends ConfigurableMacBase
       String walUri = tserverWal.toURI().toString();
       KeyExtent extent = new KeyExtent(tableId, null, null);
       try (BatchWriter bw = client.createBatchWriter(MetadataTable.NAME)) {
-        Mutation m = new Mutation(extent.getMetadataEntry());
+        Mutation m = new Mutation(extent.toMetaRow());
         m.put(LogColumnFamily.NAME, new Text("localhost:12345/" + walUri),
             new Value(walUri + "|1"));
         bw.addMutation(m);


Mime
View raw message