diff --git a/source/Lib/CommonLib/ContextModelling.h b/source/Lib/CommonLib/ContextModelling.h
index 150796090b4fc175cbfa33351287b8fa75118be4..575b2aab4bde637496fb734b73e849ce80036b47 100644
--- a/source/Lib/CommonLib/ContextModelling.h
+++ b/source/Lib/CommonLib/ContextModelling.h
@@ -448,7 +448,10 @@ public:
                          {
                            violatesLfnstConstrained[CHANNEL_TYPE_LUMA  ] = false;
                            violatesLfnstConstrained[CHANNEL_TYPE_CHROMA] = false;
-                           lfnstLastScanPos = false;
+                           lfnstLastScanPos                              = false;
+#if JVET_P1026_MTS_SIGNALLING
+                           violatesMtsCoeffConstraint                    = false;
+#endif
                          }
   CUCtx(int _qp)       : isDQPCoded(false), isChromaQpAdjCoded(false),
                          qgStart(false),
@@ -456,7 +459,10 @@ public:
                          {
                            violatesLfnstConstrained[CHANNEL_TYPE_LUMA  ] = false;
                            violatesLfnstConstrained[CHANNEL_TYPE_CHROMA] = false;
-                           lfnstLastScanPos = false;
+                           lfnstLastScanPos                              = false;
+#if JVET_P1026_MTS_SIGNALLING
+                           violatesMtsCoeffConstraint                    = false;
+#endif
                          }
   ~CUCtx() {}
 public:
@@ -466,6 +472,9 @@ public:
   bool      lfnstLastScanPos;
   int8_t    qp;                   // used as a previous(last) QP and for QP prediction
   bool      violatesLfnstConstrained[MAX_NUM_CHANNEL_TYPE];
+#if JVET_P1026_MTS_SIGNALLING
+  bool      violatesMtsCoeffConstraint;
+#endif
 };
 
 class MergeCtx
diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h
index 0cb6d479bb92b9856ba0f768bcbd22d915d610aa..e626ef8e89ac44a4860af713b9a0ce0f17911e0f 100644
--- a/source/Lib/CommonLib/TypeDef.h
+++ b/source/Lib/CommonLib/TypeDef.h
@@ -49,6 +49,9 @@
 #include <cstring>
 #include <assert.h>
 #include <cassert>
+
+#define JVET_P1026_MTS_SIGNALLING                         1 // JVET-P1026: CU level MTS signalling
+
 #define JVET_P0571_FIX_BS_BDPCM_CHROMA                    1 // JVET-P0571: align boundary strength for Chroma BDPCM
 
 #define JVET_P0983_REMOVE_SPS_SBT_MAX_SIZE_FLAG           1 // JVET-P0983/JVET-P0391: Remove sps_sbt_max_size_64_flag
diff --git a/source/Lib/CommonLib/Unit.cpp b/source/Lib/CommonLib/Unit.cpp
index 4b2874848c1270845768df01e0d40798469ca896..af23619b5ea15f8fa304513b9faf7fca99d29e05 100644
--- a/source/Lib/CommonLib/Unit.cpp
+++ b/source/Lib/CommonLib/Unit.cpp
@@ -859,10 +859,15 @@ int TransformUnit::getTbAreaAfterCoefZeroOut(ComponentID compID) const
   int tbArea = blocks[compID].width * blocks[compID].height;
   int tbZeroOutWidth = blocks[compID].width;
   int tbZeroOutHeight = blocks[compID].height;
+
+#if JVET_P1026_MTS_SIGNALLING
+  if ( cs->sps->getUseMTS() && cu->sbtInfo != 0 && blocks[compID].width <= 32 && blocks[compID].height <= 32 && !cu->transQuantBypass && compID == COMPONENT_Y )
+#else
 #if JVET_P0058_CHROMA_TS
   if ((mtsIdx[compID] > MTS_SKIP || (cs->sps->getUseMTS() && cu->sbtInfo != 0 && blocks[compID].width <= 32 && blocks[compID].height <= 32)) && !cu->transQuantBypass && compID == COMPONENT_Y)
 #else
   if ((mtsIdx > MTS_SKIP || (cs->sps->getUseMTS() && cu->sbtInfo != 0 && blocks[compID].width <= 32 && blocks[compID].height <= 32)) && !cu->transQuantBypass && compID == COMPONENT_Y)
+#endif
 #endif
   {
     tbZeroOutWidth = (blocks[compID].width == 32) ? 16 : tbZeroOutWidth;
diff --git a/source/Lib/CommonLib/UnitTools.cpp b/source/Lib/CommonLib/UnitTools.cpp
index dd49aed52a395140fc5d90784cec7693ebfb7cc8..95141fe5bfba2f4255b414d800c0391218af6fe4 100644
--- a/source/Lib/CommonLib/UnitTools.cpp
+++ b/source/Lib/CommonLib/UnitTools.cpp
@@ -3765,6 +3765,25 @@ bool CU::bdpcmAllowed( const CodingUnit& cu, const ComponentID compID )
 
   return bdpcmAllowed;
 }
+
+#if JVET_P1026_MTS_SIGNALLING
+bool CU::isMTSAllowed(const CodingUnit &cu, const ComponentID compID)
+{
+  SizeType tsMaxSize = 1 << cu.cs->pps->getLog2MaxTransformSkipBlockSize();
+  const int maxSize  = CU::isIntra( cu ) ? MTS_INTRA_MAX_CU_SIZE : MTS_INTER_MAX_CU_SIZE;
+  const int cuWidth  = cu.blocks[0].lumaSize().width;
+  const int cuHeight = cu.blocks[0].lumaSize().height;
+  bool mtsAllowed    = cu.chType == CHANNEL_TYPE_LUMA && compID == COMPONENT_Y;
+
+  mtsAllowed &= CU::isIntra( cu ) ? cu.cs->sps->getUseIntraMTS() : cu.cs->sps->getUseInterMTS() && CU::isInter( cu );
+  mtsAllowed &= cuWidth <= maxSize && cuHeight <= maxSize;
+  mtsAllowed &= !cu.ispMode;
+  mtsAllowed &= !cu.sbtInfo;
+  mtsAllowed &= !(cu.bdpcmMode && cuWidth <= tsMaxSize && cuHeight <= tsMaxSize);
+  return mtsAllowed;
+}
+#endif
+
 // TU tools
 
 bool TU::isNonTransformedResidualRotated(const TransformUnit &tu, const ComponentID &compID)
@@ -3822,6 +3841,7 @@ bool TU::isTSAllowed(const TransformUnit &tu, const ComponentID compID)
   return tsAllowed;
 }
 
+#if !JVET_P1026_MTS_SIGNALLING
 bool TU::isMTSAllowed(const TransformUnit &tu, const ComponentID compID)
 {
   bool   mtsAllowed = compID == COMPONENT_Y;
@@ -3835,6 +3855,7 @@ bool TU::isMTSAllowed(const TransformUnit &tu, const ComponentID compID)
   mtsAllowed &= !( tu.cu->bdpcmMode && tu.lwidth() <= transformSkipMaxSize && tu.lheight() <= transformSkipMaxSize);
   return mtsAllowed;
 }
+#endif
 
 int TU::getICTMode( const TransformUnit& tu, int jointCbCr )
 {
diff --git a/source/Lib/CommonLib/UnitTools.h b/source/Lib/CommonLib/UnitTools.h
index a1c766ff382a35bb7b2a6ef16892523d363d5a5d..497679860c42c1483a8f7307c98f2ac1d29d9d3c 100644
--- a/source/Lib/CommonLib/UnitTools.h
+++ b/source/Lib/CommonLib/UnitTools.h
@@ -90,6 +90,9 @@ namespace CU
   void  setGbiIdx                     (CodingUnit& cu, uint8_t uh);
   uint8_t deriveGbiIdx                (uint8_t gbiLO, uint8_t gbiL1);
   bool bdpcmAllowed                   (const CodingUnit& cu, const ComponentID compID);
+#if JVET_P1026_MTS_SIGNALLING
+  bool isMTSAllowed                   (const CodingUnit& cu, const ComponentID compID);
+#endif
 
 
   bool      divideTuInRows            ( const CodingUnit &cu );
@@ -199,7 +202,9 @@ namespace TU
   bool getCbfAtDepth                  (const TransformUnit &tu, const ComponentID &compID, const unsigned &depth);
   void setCbfAtDepth                  (      TransformUnit &tu, const ComponentID &compID, const unsigned &depth, const bool &cbf);
   bool isTSAllowed                    (const TransformUnit &tu, const ComponentID  compID);
+#if !JVET_P1026_MTS_SIGNALLING
   bool isMTSAllowed                   (const TransformUnit &tu, const ComponentID  compID);
+#endif
   bool hasCrossCompPredInfo           (const TransformUnit &tu, const ComponentID &compID);
 
 
diff --git a/source/Lib/DecoderLib/CABACReader.cpp b/source/Lib/DecoderLib/CABACReader.cpp
index 71321b20de47fecd3c0253ec760061f3cfde903a..daa3a7bc58b39492dcb3baf6c0b98e7da9b06a82 100644
--- a/source/Lib/DecoderLib/CABACReader.cpp
+++ b/source/Lib/DecoderLib/CABACReader.cpp
@@ -1510,7 +1510,10 @@ void CABACReader::cu_residual( CodingUnit& cu, Partitioner &partitioner, CUCtx&
   }
   cuCtx.violatesLfnstConstrained[CHANNEL_TYPE_LUMA]   = false;
   cuCtx.violatesLfnstConstrained[CHANNEL_TYPE_CHROMA] = false;
-  cuCtx.lfnstLastScanPos = false;
+  cuCtx.lfnstLastScanPos                              = false;
+#if JVET_P1026_MTS_SIGNALLING
+  cuCtx.violatesMtsCoeffConstraint                    = false;
+#endif
 
   ChromaCbfs chromaCbfs;
   if( cu.ispMode && isLuma( partitioner.chType ) )
@@ -1522,7 +1525,11 @@ void CABACReader::cu_residual( CodingUnit& cu, Partitioner &partitioner, CUCtx&
   {
     transform_tree( *cu.cs, partitioner, cuCtx             );
   }
+
   residual_lfnst_mode( cu, cuCtx );
+#if JVET_P1026_MTS_SIGNALLING
+  mts_idx            ( cu, cuCtx );
+#endif
 }
 
 void CABACReader::rqt_root_cbf( CodingUnit& cu )
@@ -2911,7 +2918,11 @@ void CABACReader::residual_coding( TransformUnit& tu, ComponentID compID, CUCtx&
     return;
 
   // parse transform skip and explicit rdpcm mode
+#if JVET_P1026_MTS_SIGNALLING
+  ts_flag            ( tu, compID );
+#else
   mts_coding         ( tu, compID );
+#endif
   explicit_rdpcm_mode( tu, compID );
 
 #if JVET_P0058_CHROMA_TS
@@ -2964,6 +2975,13 @@ void CABACReader::residual_coding( TransformUnit& tu, ComponentID compID, CUCtx&
     const int lfnstLastScanPosTh = isLuma( compID ) ? LFNST_LAST_SIG_LUMA : LFNST_LAST_SIG_CHROMA;
     cuCtx.lfnstLastScanPos |= cctx.scanPosLast() >= lfnstLastScanPosTh;
   }
+#if JVET_P1026_MTS_SIGNALLING
+  if( isLuma(compID) && ( cctx.posX(cctx.scanPosLast()) >= 16 || cctx.posY(cctx.scanPosLast()) >= 16 ) )
+  {
+    cuCtx.violatesMtsCoeffConstraint = true;
+  }
+#endif
+
   // parse subblocks
   const int stateTransTab = ( tu.cs->slice->getDepQuantEnabledFlag() ? 32040 : 0 );
   int       state         = 0;
@@ -2974,10 +2992,15 @@ void CABACReader::residual_coding( TransformUnit& tu, ComponentID compID, CUCtx&
     for( int subSetId = ( cctx.scanPosLast() >> cctx.log2CGSize() ); subSetId >= 0; subSetId--)
     {
       cctx.initSubblock       ( subSetId );
+
+#if JVET_P1026_MTS_SIGNALLING
+      if( tu.cs->sps->getUseMTS() && tu.cu->sbtInfo != 0 && tu.blocks[ compID ].height <= 32 && tu.blocks[ compID ].width <= 32 && !tu.cu->transQuantBypass && compID == COMPONENT_Y )
+#else
 #if JVET_P0058_CHROMA_TS
       if( ( tu.mtsIdx[compID] > MTS_SKIP || (tu.cs->sps->getUseMTS() && tu.cu->sbtInfo != 0 && tu.blocks[compID].height <= 32 && tu.blocks[compID].width <= 32)) && !tu.cu->transQuantBypass && compID == COMPONENT_Y)
 #else
       if( ( tu.mtsIdx > MTS_SKIP || ( tu.cs->sps->getUseMTS() && tu.cu->sbtInfo != 0 && tu.blocks[ compID ].height <= 32 && tu.blocks[ compID ].width <= 32 ) ) && !tu.cu->transQuantBypass && compID == COMPONENT_Y )
+#endif
 #endif
       {
         if( ( tu.blocks[ compID ].height == 32 && cctx.cgPosY() >= ( 16 >> cctx.log2CGHeight() ) ) || ( tu.blocks[ compID ].width == 32 && cctx.cgPosX() >= ( 16 >> cctx.log2CGWidth() ) ) )
@@ -2990,6 +3013,74 @@ void CABACReader::residual_coding( TransformUnit& tu, ComponentID compID, CUCtx&
 
 }
 
+#if JVET_P1026_MTS_SIGNALLING
+void CABACReader::ts_flag( TransformUnit& tu, ComponentID compID )
+{
+#if JVET_P0058_CHROMA_TS
+  int tsFlag = tu.cu->bdpcmMode && isLuma(compID) ? 1 : tu.mtsIdx[compID] == MTS_SKIP ? 1 : 0;
+  int ctxIdx = isLuma(compID) ? 6 : 11;
+#else
+  int tsFlag = tu.cu->bdpcmMode ? 1 : tu.mtsIdx == MTS_SKIP ? 1 : 0;
+  int ctxIdx = 6;
+#endif
+
+  if( TU::isTSAllowed ( tu, compID ) )
+  {
+    RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET_SIZE2( STATS__CABAC_BITS__MTS_FLAGS, tu.blocks[compID], compID );
+    tsFlag = m_BinDecoder.decodeBin( Ctx::MTSIndex( ctxIdx ) );
+  }
+  
+#if JVET_P0058_CHROMA_TS
+  tu.mtsIdx[compID] = tsFlag ? MTS_SKIP : MTS_DCT2_DCT2;
+#else
+  tu.mtsIdx = tsFlag ? MTS_SKIP : MTS_DCT2_DCT2;
+#endif
+  
+  DTRACE(g_trace_ctx, D_SYNTAX, "ts_flag() etype=%d pos=(%d,%d) mtsIdx=%d\n", COMPONENT_Y, tu.cu->lx(), tu.cu->ly(), tsFlag);
+}
+
+void CABACReader::mts_idx( CodingUnit& cu, CUCtx& cuCtx )
+{
+  TransformUnit &tu = *cu.firstTU;
+#if JVET_P0058_CHROMA_TS
+  int        mtsIdx = tu.mtsIdx[COMPONENT_Y]; // Transform skip flag has already been decoded
+#else
+  int        mtsIdx = tu.mtsIdx;              // Transform skip flag has already been decoded
+#endif
+  
+  if( CU::isMTSAllowed( cu, COMPONENT_Y ) && !cuCtx.violatesMtsCoeffConstraint &&
+      cu.lfnstIdx == 0 && mtsIdx != MTS_SKIP && TU::getCbf(tu, COMPONENT_Y) )
+  {
+    RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET_SIZE2( STATS__CABAC_BITS__MTS_FLAGS, tu.blocks[COMPONENT_Y], COMPONENT_Y );
+    int ctxIdx = 0;
+    int symbol = m_BinDecoder.decodeBin( Ctx::MTSIndex( ctxIdx ) );
+    
+    if( symbol )
+    {
+      ctxIdx = 7;
+      mtsIdx = MTS_DST7_DST7; // mtsIdx = 2 -- 4
+      for( int i = 0; i < 3; i++, ctxIdx++ )
+      {
+        symbol  = m_BinDecoder.decodeBin( Ctx::MTSIndex( ctxIdx ) );
+        mtsIdx += symbol;
+        
+        if( !symbol )
+        {
+          break;
+        }
+      }
+    }
+  }
+  
+#if JVET_P0058_CHROMA_TS
+  tu.mtsIdx[COMPONENT_Y] = mtsIdx;
+#else
+  tu.mtsIdx = mtsIdx;
+#endif
+  
+  DTRACE(g_trace_ctx, D_SYNTAX, "mts_idx() etype=%d pos=(%d,%d) mtsIdx=%d\n", COMPONENT_Y, tu.cu->lx(), tu.cu->ly(), mtsIdx);
+}
+#else
 void CABACReader::mts_coding( TransformUnit& tu, ComponentID compID )
 {
   const bool  tsAllowed = TU::isTSAllowed ( tu, compID );
@@ -3063,7 +3154,8 @@ void CABACReader::mts_coding( TransformUnit& tu, ComponentID compID )
   DTRACE(g_trace_ctx, D_SYNTAX, "mts_coding() etype=%d pos=(%d,%d) mtsIdx=%d\n", COMPONENT_Y, tu.cu->lx(), tu.cu->ly(), tu.mtsIdx);
 #endif
 }
-
+#endif
+  
 void CABACReader::isp_mode( CodingUnit& cu )
 {
   if( !CU::isIntra( cu ) || !isLuma( cu.chType ) || cu.firstPU->multiRefIdx || !cu.cs->sps->getUseISP() || cu.bdpcmMode || !CU::canUseISP( cu, getFirstComponentOfChannel( cu.chType ) ) )
@@ -3132,12 +3224,21 @@ void CABACReader::residual_lfnst_mode( CodingUnit& cu,  CUCtx& cuCtx  )
     const bool lumaFlag              = cu.isSepTree() ? (   isLuma( cu.chType ) ? true : false ) : true;
     const bool chromaFlag            = cu.isSepTree() ? ( isChroma( cu.chType ) ? true : false ) : true;
     bool nonZeroCoeffNonTsCorner8x8 = ( lumaFlag && cuCtx.violatesLfnstConstrained[CHANNEL_TYPE_LUMA] ) || (chromaFlag && cuCtx.violatesLfnstConstrained[CHANNEL_TYPE_CHROMA] );
+#if JVET_P1026_MTS_SIGNALLING
+#if JVET_P0058_CHROMA_TS
+    const bool isTrSkip = TU::getCbf(*cu.firstTU, COMPONENT_Y) && cu.firstTU->mtsIdx[COMPONENT_Y] == MTS_SKIP;
+#else
+    const bool isTrSkip = TU::getCbf(*cu.firstTU, COMPONENT_Y) && cu.firstTU->mtsIdx == MTS_SKIP;
+#endif
+    if( !cuCtx.lfnstLastScanPos || nonZeroCoeffNonTsCorner8x8 || isTrSkip )
+#else
 #if JVET_P0058_CHROMA_TS
     const bool isNonDCT2 = (TU::getCbf(*cu.firstTU, ComponentID(COMPONENT_Y)) && cu.firstTU->mtsIdx[COMPONENT_Y] != MTS_DCT2_DCT2);
 #else
     const bool isNonDCT2 = (TU::getCbf(*cu.firstTU, ComponentID(COMPONENT_Y)) && cu.firstTU->mtsIdx != MTS_DCT2_DCT2);
 #endif
     if( !cuCtx.lfnstLastScanPos || nonZeroCoeffNonTsCorner8x8 || isNonDCT2 )
+#endif
     {
       cu.lfnstIdx = 0;
       return;
@@ -3171,10 +3272,14 @@ int CABACReader::last_sig_coeff( CoeffCodingContext& cctx, TransformUnit& tu, Co
   unsigned maxLastPosX = cctx.maxLastPosX();
   unsigned maxLastPosY = cctx.maxLastPosY();
 
+#if JVET_P1026_MTS_SIGNALLING
+  if( tu.cs->sps->getUseMTS() && tu.cu->sbtInfo != 0 && tu.blocks[ compID ].width <= 32 && tu.blocks[ compID ].height <= 32 && !tu.cu->transQuantBypass && compID == COMPONENT_Y )
+#else
 #if JVET_P0058_CHROMA_TS
   if( ( tu.mtsIdx[compID] > MTS_SKIP || (tu.cs->sps->getUseMTS() && tu.cu->sbtInfo != 0 && tu.blocks[compID].width <= 32 && tu.blocks[compID].height <= 32)) && !tu.cu->transQuantBypass && compID == COMPONENT_Y)
 #else
   if( ( tu.mtsIdx > MTS_SKIP || ( tu.cs->sps->getUseMTS() && tu.cu->sbtInfo != 0 && tu.blocks[ compID ].width <= 32 && tu.blocks[ compID ].height <= 32 ) ) && !tu.cu->transQuantBypass && compID == COMPONENT_Y )
+#endif
 #endif
   {
     maxLastPosX = ( tu.blocks[ compID ].width  == 32 ) ? g_uiGroupIdx[ 15 ] : maxLastPosX;
diff --git a/source/Lib/DecoderLib/CABACReader.h b/source/Lib/DecoderLib/CABACReader.h
index e6e1d6018b9a99d1ef72c474e4c9d76239ad557e..095bd04fc3f7f078982d3365fdd616fd5c8ebc89 100644
--- a/source/Lib/DecoderLib/CABACReader.h
+++ b/source/Lib/DecoderLib/CABACReader.h
@@ -132,7 +132,12 @@ public:
 
   // residual coding (clause 7.3.8.11)
   void        residual_coding           ( TransformUnit&                tu,     ComponentID     compID, CUCtx& cuCtx );
+#if JVET_P1026_MTS_SIGNALLING
+  void        ts_flag                   ( TransformUnit&                tu,     ComponentID     compID );
+  void        mts_idx                   ( CodingUnit&                   cu,     CUCtx&          cuCtx  );
+#else
   void        mts_coding                ( TransformUnit&                tu,     ComponentID     compID );
+#endif
   void        residual_lfnst_mode       ( CodingUnit&                   cu,     CUCtx&          cuCtx  );
   void        isp_mode                  ( CodingUnit&                   cu );
   void        explicit_rdpcm_mode       ( TransformUnit&                tu,     ComponentID     compID );
diff --git a/source/Lib/EncoderLib/CABACWriter.cpp b/source/Lib/EncoderLib/CABACWriter.cpp
index bcaf7e21c3430334cd2022b9122aee7fcb02271b..1b736e54bf7eba965c525f8554e91bd821290f12 100644
--- a/source/Lib/EncoderLib/CABACWriter.cpp
+++ b/source/Lib/EncoderLib/CABACWriter.cpp
@@ -1275,7 +1275,10 @@ void CABACWriter::cu_residual( const CodingUnit& cu, Partitioner& partitioner, C
 
   cuCtx.violatesLfnstConstrained[CHANNEL_TYPE_LUMA]   = false;
   cuCtx.violatesLfnstConstrained[CHANNEL_TYPE_CHROMA] = false;
-  cuCtx.lfnstLastScanPos = false;
+  cuCtx.lfnstLastScanPos                              = false;
+#if JVET_P1026_MTS_SIGNALLING
+  cuCtx.violatesMtsCoeffConstraint                    = false;
+#endif
 
   if( cu.ispMode && isLuma( partitioner.chType ) )
   {
@@ -1288,6 +1291,9 @@ void CABACWriter::cu_residual( const CodingUnit& cu, Partitioner& partitioner, C
   }
 
   residual_lfnst_mode( cu, cuCtx );
+#if JVET_P1026_MTS_SIGNALLING
+  mts_idx            ( cu, cuCtx );
+#endif
 }
 
 void CABACWriter::rqt_root_cbf( const CodingUnit& cu )
@@ -2681,7 +2687,11 @@ void CABACWriter::residual_coding( const TransformUnit& tu, ComponentID compID,
     return;
 
   // code transform skip and explicit rdpcm mode
+#if JVET_P1026_MTS_SIGNALLING
+  ts_flag            ( tu, compID );
+#else
   mts_coding         ( tu, compID );
+#endif
   explicit_rdpcm_mode( tu, compID );
 
 #if JVET_P0058_CHROMA_TS
@@ -2747,6 +2757,13 @@ void CABACWriter::residual_coding( const TransformUnit& tu, ComponentID compID,
     const int lfnstLastScanPosTh = isLuma( compID ) ? LFNST_LAST_SIG_LUMA : LFNST_LAST_SIG_CHROMA;
     cuCtx->lfnstLastScanPos |= cctx.scanPosLast() >= lfnstLastScanPosTh;
   }
+#if JVET_P1026_MTS_SIGNALLING
+  if( cuCtx && isLuma(compID) && ( cctx.posX(cctx.scanPosLast()) >= 16 || cctx.posY(cctx.scanPosLast()) >= 16 ) )
+  {
+    cuCtx->violatesMtsCoeffConstraint = true;
+  }
+#endif
+  
   // code last coeff position
   last_sig_coeff( cctx, tu, compID );
 
@@ -2760,11 +2777,16 @@ void CABACWriter::residual_coding( const TransformUnit& tu, ComponentID compID,
   for( int subSetId = ( cctx.scanPosLast() >> cctx.log2CGSize() ); subSetId >= 0; subSetId--)
   {
     cctx.initSubblock       ( subSetId, sigGroupFlags[subSetId] );
+
+#if JVET_P1026_MTS_SIGNALLING
+    if( tu.cs->sps->getUseMTS() && tu.cu->sbtInfo != 0 && tu.blocks[ compID ].height <= 32 && tu.blocks[ compID ].width <= 32 && !tu.cu->transQuantBypass && compID == COMPONENT_Y )
+#else
 #if JVET_P0058_CHROMA_TS
     if( ( tu.mtsIdx[compID] > MTS_SKIP || (tu.cs->sps->getUseMTS() && tu.cu->sbtInfo != 0 && tu.blocks[compID].height <= 32 && tu.blocks[compID].width <= 32)) && !tu.cu->transQuantBypass && compID == COMPONENT_Y)
 #else
     if( ( tu.mtsIdx > MTS_SKIP || ( tu.cs->sps->getUseMTS() && tu.cu->sbtInfo != 0 && tu.blocks[ compID ].height <= 32 && tu.blocks[ compID ].width <= 32 ) ) && !tu.cu->transQuantBypass && compID == COMPONENT_Y )
-#endif    
+#endif
+#endif
     {
       if( ( tu.blocks[ compID ].height == 32 && cctx.cgPosY() >= ( 16 >> cctx.log2CGHeight() ) )
        || ( tu.blocks[ compID ].width  == 32 && cctx.cgPosX() >= ( 16 >> cctx.log2CGWidth()  ) ) )
@@ -2776,6 +2798,59 @@ void CABACWriter::residual_coding( const TransformUnit& tu, ComponentID compID,
   }
 }
 
+#if JVET_P1026_MTS_SIGNALLING
+void CABACWriter::ts_flag( const TransformUnit& tu, ComponentID compID )
+{
+#if JVET_P0058_CHROMA_TS
+  int tsFlag = tu.mtsIdx[compID] == MTS_SKIP ? 1 : 0;
+  int ctxIdx = isLuma(compID) ? 6 : 11;
+#else
+  int tsFlag = tu.mtsIdx == MTS_SKIP ? 1 : 0;
+  int ctxIdx = 6;
+#endif
+  
+  if( TU::isTSAllowed ( tu, compID ) )
+  {
+    m_BinEncoder.encodeBin( tsFlag, Ctx::MTSIndex( ctxIdx ) );
+  }
+  DTRACE( g_trace_ctx, D_SYNTAX, "ts_flag() etype=%d pos=(%d,%d) mtsIdx=%d\n", COMPONENT_Y, tu.cu->lx(), tu.cu->ly(), tsFlag );
+}
+
+void CABACWriter::mts_idx( const CodingUnit& cu, CUCtx& cuCtx )
+{
+  TransformUnit &tu = *cu.firstTU;
+#if JVET_P0058_CHROMA_TS
+  int        mtsIdx = tu.mtsIdx[COMPONENT_Y];
+#else
+  int        mtsIdx = tu.mtsIdx;
+#endif
+  
+  if( CU::isMTSAllowed( cu, COMPONENT_Y ) && !cuCtx.violatesMtsCoeffConstraint &&
+      cu.lfnstIdx == 0 && mtsIdx != MTS_SKIP && TU::getCbf(tu, COMPONENT_Y) )
+  {
+    int symbol = mtsIdx != MTS_DCT2_DCT2 ? 1 : 0;
+    int ctxIdx = 0;
+    
+    m_BinEncoder.encodeBin( symbol, Ctx::MTSIndex( ctxIdx ) );
+    
+    if( symbol )
+    {
+      ctxIdx = 7;
+      for( int i = 0; i < 3; i++, ctxIdx++ )
+      {
+        symbol = mtsIdx > i + MTS_DST7_DST7 ? 1 : 0;
+        m_BinEncoder.encodeBin( symbol, Ctx::MTSIndex( ctxIdx ) );
+        
+        if( !symbol )
+        {
+          break;
+        }
+      }
+    }
+  }
+  DTRACE( g_trace_ctx, D_SYNTAX, "mts_idx() etype=%d pos=(%d,%d) mtsIdx=%d\n", COMPONENT_Y, tu.cu->lx(), tu.cu->ly(), mtsIdx);
+}
+#else
 void CABACWriter::mts_coding( const TransformUnit& tu, ComponentID compID )
 {
   const bool  tsAllowed = TU::isTSAllowed ( tu, compID );
@@ -2844,6 +2919,7 @@ void CABACWriter::mts_coding( const TransformUnit& tu, ComponentID compID )
   DTRACE( g_trace_ctx, D_SYNTAX, "mts_coding() etype=%d pos=(%d,%d) mtsIdx=%d\n", COMPONENT_Y, tu.cu->lx(), tu.cu->ly(), tu.mtsIdx);
 #endif
 }
+#endif
 
 void CABACWriter::isp_mode( const CodingUnit& cu )
 {
@@ -2907,12 +2983,22 @@ void CABACWriter::residual_lfnst_mode( const CodingUnit& cu, CUCtx& cuCtx )
     const bool lumaFlag                   = cu.isSepTree() ? (   isLuma( cu.chType ) ? true : false ) : true;
     const bool chromaFlag                 = cu.isSepTree() ? ( isChroma( cu.chType ) ? true : false ) : true;
           bool nonZeroCoeffNonTsCorner8x8 = ( lumaFlag && cuCtx.violatesLfnstConstrained[CHANNEL_TYPE_LUMA] ) || (chromaFlag && cuCtx.violatesLfnstConstrained[CHANNEL_TYPE_CHROMA] );
+
+#if JVET_P1026_MTS_SIGNALLING
+#if JVET_P0058_CHROMA_TS
+    const bool isTrSkip = TU::getCbf(*cu.firstTU, COMPONENT_Y) && cu.firstTU->mtsIdx[COMPONENT_Y] == MTS_SKIP;
+#else
+    const bool isTrSkip = TU::getCbf(*cu.firstTU, COMPONENT_Y) && cu.firstTU->mtsIdx == MTS_SKIP;
+#endif
+    if( !cuCtx.lfnstLastScanPos || nonZeroCoeffNonTsCorner8x8 || isTrSkip )
+#else
 #if JVET_P0058_CHROMA_TS
     const bool isNonDCT2 = (TU::getCbf(*cu.firstTU, ComponentID(COMPONENT_Y)) && cu.firstTU->mtsIdx[COMPONENT_Y] != MTS_DCT2_DCT2);
 #else
     const bool isNonDCT2 = (TU::getCbf(*cu.firstTU, ComponentID(COMPONENT_Y)) && cu.firstTU->mtsIdx != MTS_DCT2_DCT2);
 #endif
     if( !cuCtx.lfnstLastScanPos || nonZeroCoeffNonTsCorner8x8 || isNonDCT2 )
+#endif
     {
       return;
     }
@@ -2954,10 +3040,14 @@ void CABACWriter::last_sig_coeff( CoeffCodingContext& cctx, const TransformUnit&
   unsigned maxLastPosX = cctx.maxLastPosX();
   unsigned maxLastPosY = cctx.maxLastPosY();
 
+#if JVET_P1026_MTS_SIGNALLING
+  if( tu.cs->sps->getUseMTS() && tu.cu->sbtInfo != 0 && tu.blocks[ compID ].width <= 32 && tu.blocks[ compID ].height <= 32 && !tu.cu->transQuantBypass && compID == COMPONENT_Y )
+#else
 #if JVET_P0058_CHROMA_TS
   if ((tu.mtsIdx[compID] > MTS_SKIP || (tu.cs->sps->getUseMTS() && tu.cu->sbtInfo != 0 && tu.blocks[compID].width <= 32 && tu.blocks[compID].height <= 32)) && !tu.cu->transQuantBypass && compID == COMPONENT_Y)
 #else
   if( ( tu.mtsIdx > MTS_SKIP || ( tu.cs->sps->getUseMTS() && tu.cu->sbtInfo != 0 && tu.blocks[ compID ].width <= 32 && tu.blocks[ compID ].height <= 32 ) ) && !tu.cu->transQuantBypass && compID == COMPONENT_Y )
+#endif
 #endif
   {
     maxLastPosX = ( tu.blocks[compID].width  == 32 ) ? g_uiGroupIdx[ 15 ] : maxLastPosX;
diff --git a/source/Lib/EncoderLib/CABACWriter.h b/source/Lib/EncoderLib/CABACWriter.h
index d1821b30a1e4e6eb17dfba6de2c0da93a6dd69d3..b18e45737a0062dc83337058494de56ed0de5b36 100644
--- a/source/Lib/EncoderLib/CABACWriter.h
+++ b/source/Lib/EncoderLib/CABACWriter.h
@@ -143,7 +143,12 @@ public:
 
   // residual coding (clause 7.3.8.11)
   void        residual_coding           ( const TransformUnit&          tu,       ComponentID       compID, CUCtx* cuCtx = nullptr );
+#if JVET_P1026_MTS_SIGNALLING
+  void        ts_flag                   ( const TransformUnit&          tu,       ComponentID       compID );
+  void        mts_idx                   ( const CodingUnit&             cu,       CUCtx&            cuCtx  );
+#else
   void        mts_coding                ( const TransformUnit&          tu,       ComponentID       compID );
+#endif
   void        residual_lfnst_mode       ( const CodingUnit&             cu,       CUCtx&            cuCtx );
   void        isp_mode                  ( const CodingUnit&             cu );
   void        explicit_rdpcm_mode       ( const TransformUnit&          tu,       ComponentID       compID );
diff --git a/source/Lib/EncoderLib/InterSearch.cpp b/source/Lib/EncoderLib/InterSearch.cpp
index d676186951573d7be8a93f6ba38d258e7c39a4d4..bc7f0248d55c9de9d59615d867c69d4a862ef352 100644
--- a/source/Lib/EncoderLib/InterSearch.cpp
+++ b/source/Lib/EncoderLib/InterSearch.cpp
@@ -6569,7 +6569,12 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par
 #else
       const bool tsAllowed  = TU::isTSAllowed ( tu, compID );
 #endif
+#if JVET_P1026_MTS_SIGNALLING
+      const bool mtsAllowed = CU::isMTSAllowed( *tu.cu, compID );
+#else
       const bool mtsAllowed = TU::isMTSAllowed( tu, compID );
+#endif
+      
       uint8_t nNumTransformCands = 1 + ( tsAllowed ? 1 : 0 ) + ( mtsAllowed ? 4 : 0 ); // DCT + TS + 4 MTS = 6 tests
       std::vector<TrMode> trModes;
       trModes.push_back( TrMode( 0, true ) ); //DCT2
diff --git a/source/Lib/EncoderLib/IntraSearch.cpp b/source/Lib/EncoderLib/IntraSearch.cpp
index f42818d9a60301890ec12849eff39a2bd6cf951a..71202a6f7f3f80acbabc53b91ad023bacb7debbf 100644
--- a/source/Lib/EncoderLib/IntraSearch.cpp
+++ b/source/Lib/EncoderLib/IntraSearch.cpp
@@ -2175,6 +2175,15 @@ void IntraSearch::xEncCoeffQT( CodingStructure &cs, Partitioner &partitioner, co
     }
     if( TU::getCbf( currTU, compID ) )
     {
+#if JVET_P1026_MTS_SIGNALLING
+      if( isLuma(compID) )
+      {
+        CUCtx cuCtx;
+        m_CABACEstimator->residual_coding( currTU, compID, &cuCtx );
+        m_CABACEstimator->mts_idx( *currTU.cu, cuCtx );
+      }
+      else
+#endif
       m_CABACEstimator->residual_coding( currTU, compID );
     }
   }
@@ -2790,7 +2799,11 @@ bool IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par
     tu.depth = currDepth;
 
     const bool tsAllowed  = TU::isTSAllowed( tu, COMPONENT_Y );
+#if JVET_P1026_MTS_SIGNALLING
+    const bool mtsAllowed = CU::isMTSAllowed( cu, COMPONENT_Y );
+#else
     const bool mtsAllowed = TU::isMTSAllowed( tu, COMPONENT_Y );
+#endif
     std::vector<TrMode> trModes;
 
     if( sps.getUseLFNST() )