diff --git a/io/io/inc/TStreamerInfoActions.h b/io/io/inc/TStreamerInfoActions.h
index 68b7ead967171d7f176e1b5d377a047cf354ee89..b0e8c5419ae211d76fdef5a798c2efdc2ee8c9d3 100644
--- a/io/io/inc/TStreamerInfoActions.h
+++ b/io/io/inc/TStreamerInfoActions.h
@@ -13,6 +13,7 @@
 #define ROOT_TStreamerInfoActions
 
 #include <vector>
+#include <ROOT/RMakeUnique.hxx>
 
 #include "TStreamerInfo.h"
 #include <assert.h>
@@ -50,12 +51,17 @@ namespace TStreamerInfoActions {
    /// Base class of the Configurations for the member wise looping routines.
    class TLoopConfiguration {
    public:
-      TLoopConfiguration() {};
+      TVirtualCollectionProxy *fProxy = nullptr;
+   public:
+      TLoopConfiguration() = default;
+      TLoopConfiguration(TVirtualCollectionProxy *proxy) : fProxy(proxy) {}
+
       // virtual void PrintDebug(TBuffer &buffer, void *object) const;
       virtual ~TLoopConfiguration() {};
       virtual void Print() const;
       virtual void *GetFirstAddress(void *start, const void *end) const = 0;
-      virtual TLoopConfiguration* Copy() = 0; // { return new TLoopConfiguration(*this); }
+      virtual TLoopConfiguration* Copy() const = 0; // { return new TLoopConfiguration(*this); }
+      virtual TVirtualCollectionProxy* GetCollectionProxy() const { return fProxy; }
    };
 
    typedef TVirtualCollectionProxy::Next_t Next_t;
@@ -127,10 +133,43 @@ namespace TStreamerInfoActions {
       ClassDef(TConfiguredAction,0); // A configured action
    };
 
+   struct TIDNode;
+   using TIDs = std::vector<TIDNode>;
+
+   // Hold information about unfolded/extracted StreamerElement for
+   // a sub-object
+   struct TNestedIDs {
+      TNestedIDs() = default;
+      TNestedIDs(TStreamerInfo *info, Int_t offset) : fInfo(info), fOffset(offset) {}
+
+      TStreamerInfo *fInfo = nullptr; ///< Not owned.
+      TVirtualArray *fOnfileObject = nullptr; ///< Not owned.
+      Int_t          fOffset;
+      TIDs           fIDs;
+   };
+
+   // A 'node' in the list of StreamerElement ID, either
+   // the index of the element in the current streamerInfo
+   // or a set of unfolded/extracted StreamerElement for a sub-object.
+   struct TIDNode {
+      TIDNode() = default;
+      TIDNode(Int_t id) : fElemID(id), fElement(nullptr), fInfo(nullptr) {}
+      TIDNode(TStreamerInfo *info, Int_t offset) : fElemID(-1), fElement(nullptr), fInfo(nullptr)  {
+         fNestedIDs = std::make_unique<TNestedIDs>(info, offset);
+      }
+      Int_t fElemID = -1;
+      TStreamerElement *fElement = nullptr;
+      TStreamerInfo *fInfo = nullptr;
+      std::unique_ptr<TNestedIDs> fNestedIDs;
+   };
+
    typedef std::vector<TConfiguredAction> ActionContainer_t;
    class TActionSequence : public TObject {
       TActionSequence() {};
    public:
+      struct SequencePtr;
+      using SequenceGetter_t = SequencePtr(*)(TStreamerInfo *info, TVirtualCollectionProxy *collectionProxy, TClass *originalClass);
+
       TActionSequence(TVirtualStreamerInfo *info, UInt_t maxdata) : fStreamerInfo(info), fLoopConfig(0) { fActions.reserve(maxdata); };
       ~TActionSequence() {
          delete fLoopConfig;
@@ -155,8 +194,63 @@ namespace TStreamerInfoActions {
       static TActionSequence *CreateWriteMemberWiseActions(TVirtualStreamerInfo *info, TVirtualCollectionProxy &proxy);
       TActionSequence *CreateSubSequence(const std::vector<Int_t> &element_ids, size_t offset);
 
+      TActionSequence *CreateSubSequence(const TIDs &element_ids, size_t offset, SequenceGetter_t create);
+      void AddToSubSequence(TActionSequence *sequence, const TIDs &element_ids, Int_t offset, SequenceGetter_t create);
+
       void Print(Option_t * = "") const;
 
+      // Maybe owner unique_ptr
+      struct SequencePtr {
+         TStreamerInfoActions::TActionSequence *fSequence = nullptr;
+         Bool_t fOwner = kFALSE;
+
+         SequencePtr() = default;
+         SequencePtr(TStreamerInfoActions::TActionSequence *sequence,  Bool_t owner) : fSequence(sequence), fOwner(owner) {}
+
+         ~SequencePtr() {
+            if (fOwner) delete fSequence;
+         }
+
+         // Accessor to the pointee.
+         TStreamerInfoActions::TActionSequence &operator*() const {
+            return *fSequence;
+         }
+
+         // Accessor to the pointee
+         TStreamerInfoActions::TActionSequence *operator->() const {
+            return fSequence;
+         }
+
+         // Return true is the pointee is not nullptr.
+         operator bool() {
+            return fSequence != nullptr;
+         }
+      };
+
+      // SequenceGetter_t implementations
+
+      static SequencePtr ReadMemberWiseActionsCollectionGetter(TStreamerInfo *info, TVirtualCollectionProxy * /* collectionProxy */, TClass * /* originalClass */) {
+         auto seq = info->GetReadMemberWiseActions(kTRUE);
+         return {seq, kFALSE};
+      }
+      static SequencePtr ConversionReadMemberWiseActionsViaProxyGetter(TStreamerInfo *info, TVirtualCollectionProxy *collectionProxy, TClass *originalClass) {
+         auto seq = collectionProxy->GetConversionReadMemberWiseActions(originalClass, info->GetClassVersion());
+         return {seq, kFALSE};
+      }
+      static SequencePtr ReadMemberWiseActionsViaProxyGetter(TStreamerInfo *info, TVirtualCollectionProxy *collectionProxy, TClass * /* originalClass */) {
+         auto seq = collectionProxy->GetReadMemberWiseActions(info->GetClassVersion());
+         return {seq, kFALSE};
+      }
+      static SequencePtr ReadMemberWiseActionsCollectionCreator(TStreamerInfo *info, TVirtualCollectionProxy *collectionProxy, TClass * /* originalClass */) {
+         auto seq = TStreamerInfoActions::TActionSequence::CreateReadMemberWiseActions(info,*collectionProxy);
+         return {seq, kTRUE};
+      }
+      // Creator5() = Creator1;
+      static SequencePtr ReadMemberWiseActionsGetter(TStreamerInfo *info, TVirtualCollectionProxy * /* collectionProxy */, TClass * /* originalClass */) {
+         auto seq = info->GetReadMemberWiseActions(kFALSE);
+         return {seq, kFALSE};
+      }
+
       ClassDef(TActionSequence,0);
    };
 
diff --git a/io/io/src/TStreamerInfoActions.cxx b/io/io/src/TStreamerInfoActions.cxx
index 31352719c795efed4bff2f4109a66621822d5646..7d45f5a5b468af8adeffdba102e9d07c3c537fa2 100644
--- a/io/io/src/TStreamerInfoActions.cxx
+++ b/io/io/src/TStreamerInfoActions.cxx
@@ -998,7 +998,7 @@ namespace TStreamerInfoActions
    public:
       Long_t fIncrement; // Either a value to increase the cursor by and
    public:
-      TVectorLoopConfig(Long_t increment, Bool_t /* read */) : fIncrement(increment) {};
+      TVectorLoopConfig(TVirtualCollectionProxy *proxy, Long_t increment, Bool_t /* read */) : TLoopConfiguration(proxy), fIncrement(increment) {};
       //virtual void PrintDebug(TBuffer &buffer, void *);
       virtual ~TVectorLoopConfig() {};
       void Print() const
@@ -1013,23 +1013,20 @@ namespace TStreamerInfoActions
          return start;
       }
 
-      virtual TLoopConfiguration* Copy() { return new TVectorLoopConfig(*this); }
+      virtual TLoopConfiguration* Copy() const { return new TVectorLoopConfig(*this); }
    };
 
    class TAssocLoopConfig : public TLoopConfiguration {
       // Base class of the Configurations used in member wise streaming.
-   protected:
-   public:
-      TVirtualCollectionProxy *fProxy;
    public:
-      TAssocLoopConfig(TVirtualCollectionProxy *proxy, Bool_t /* read */) : fProxy(proxy) {};
+      TAssocLoopConfig(TVirtualCollectionProxy *proxy, Bool_t /* read */) : TLoopConfiguration(proxy) {};
       //virtual void PrintDebug(TBuffer &buffer, void *);
       virtual ~TAssocLoopConfig() {};
       void Print() const
       {
          printf("TAssocLoopConfig: proxy=%s\n",fProxy->GetCollectionClass()->GetName());
       }
-      virtual TLoopConfiguration* Copy() { return new TAssocLoopConfig(*this); }
+      virtual TLoopConfiguration* Copy() const { return new TAssocLoopConfig(*this); }
 
       void* GetFirstAddress(void *start, const void * /* end */) const
       {
@@ -1063,12 +1060,11 @@ namespace TStreamerInfoActions
          }
       }
    public:
-      TVirtualCollectionProxy                      *fProxy;
       TVirtualCollectionProxy::Next_t               fNext;
       TVirtualCollectionProxy::CopyIterator_t       fCopyIterator;
       TVirtualCollectionProxy::DeleteIterator_t     fDeleteIterator;
 
-      TGenericLoopConfig(TVirtualCollectionProxy *proxy, Bool_t read) : fProxy(proxy), fNext(0), fCopyIterator(0), fDeleteIterator(0)
+      TGenericLoopConfig(TVirtualCollectionProxy *proxy, Bool_t read) : TLoopConfiguration(proxy), fNext(0), fCopyIterator(0), fDeleteIterator(0)
       {
          Init(read);
       }
@@ -1077,7 +1073,7 @@ namespace TStreamerInfoActions
       {
          printf("TGenericLoopConfig: proxy=%s\n",fProxy->GetCollectionClass()->GetName());
       }
-      virtual TLoopConfiguration* Copy() { return new TGenericLoopConfig(*this); }
+      virtual TLoopConfiguration* Copy() const { return new TGenericLoopConfig(*this); }
 
       void* GetFirstAddress(void *start_collection, const void *end_collection) const
       {
@@ -1440,6 +1436,71 @@ namespace TStreamerInfoActions
       }
    };
 
+   class TConfigurationPushDataCache : public TConfiguration {
+      // Configuration object for the PushDataCache case.
+   public:
+      TVirtualArray *fOnfileObject;
+
+      TConfigurationPushDataCache(TVirtualStreamerInfo *info, TVirtualArray *onfileObject, Int_t offset) :
+         TConfiguration(info, -1, nullptr, offset), fOnfileObject(onfileObject)
+      {}
+
+      virtual void Print() const {
+         TStreamerInfo *info = (TStreamerInfo*)fInfo;
+         if (fOnfileObject)
+            printf("StreamerInfoAction, class:%s, PushDataCache offset=%d\n",
+                   info->GetClass()->GetName(), fOffset);
+         else
+            printf("StreamerInfoAction, class:%s, PopDataCache offset=%d\n",
+                   info->GetClass()->GetName(), fOffset);
+      }
+      virtual void PrintDebug(TBuffer &buffer, void *object) const {
+         if (gDebug > 1) {
+            TStreamerInfo *info = (TStreamerInfo*)fInfo;
+            printf("StreamerInfoAction, class:%s, %sDataCache, bufpos=%d, arr=%p, offset=%d, onfileObject=%p\n",
+                  info->GetClass()->GetName(), fOnfileObject ? "Push" : "Pop", buffer.Length(), object, fOffset, fOnfileObject);
+
+         }
+      }
+   };
+
+   Int_t PushDataCache(TBuffer &b, void *, const TConfiguration *conf)
+   {
+      TConfigurationPushDataCache *config = (TConfigurationPushDataCache*)conf;
+      auto onfileObject = config->fOnfileObject;
+
+      // onfileObject->SetSize(1);
+      b.PushDataCache( onfileObject );
+
+      return 0;
+   }
+
+   Int_t PushDataCacheGenericCollection(TBuffer &b, void *, const void *, const TLoopConfiguration *loopconfig, const TConfiguration *conf)
+   {
+      TConfigurationPushDataCache *config = (TConfigurationPushDataCache*)conf;
+      auto onfileObject = config->fOnfileObject;
+
+      TVirtualCollectionProxy *proxy = ((TGenericLoopConfig*)loopconfig)->fProxy;
+      UInt_t n = proxy->Size();
+
+      onfileObject->SetSize(n);
+      b.PushDataCache( onfileObject );
+
+      return 0;
+   }
+
+   Int_t PopDataCache(TBuffer &b, void *, const TConfiguration *)
+   {
+      b.PopDataCache();
+      return 0;
+   }
+
+   Int_t PopDataCacheGenericCollection(TBuffer &b, void *, const void *, const TLoopConfiguration *, const TConfiguration *)
+   {
+      b.PopDataCache();
+      return 0;
+   }
+
    class TConfigurationUseCache : public TConfiguration {
       // Configuration object for the UseCache case.
    public:
@@ -1469,7 +1530,6 @@ namespace TStreamerInfoActions
       }
    };
 
-
    INLINE_TEMPLATE_ARGS Int_t UseCache(TBuffer &b, void *addr, const TConfiguration *conf)
    {
       TConfigurationUseCache *config = (TConfigurationUseCache*)conf;
@@ -1506,7 +1566,7 @@ namespace TStreamerInfoActions
          UInt_t n = (((void**)end)-((void**)start));
          info->ReadBufferSkip(b,&ptr,config->fCompInfo,conf->fCompInfo->fType+TStreamerInfo::kSkip,aElement,n,0);
       } else {
-         TVectorLoopConfig cached_config( cached->fClass->Size(), /* read */ kTRUE );
+         TVectorLoopConfig cached_config( nullptr, cached->fClass->Size(), /* read */ kTRUE );
          void *cached_start = (*cached)[0];
          void *cached_end = ((char*)cached_start) + cached->fSize * cached_config.fIncrement;
          config->fAction(b,cached_start,cached_end,&cached_config);
@@ -1532,7 +1592,7 @@ namespace TStreamerInfoActions
          UInt_t n = (((char*)end)-((char*)start))/((TVectorLoopConfig*)loopconf)->fIncrement;
          info->ReadBufferSkip(b,&ptr,config->fCompInfo,config->fCompInfo->fType+TStreamerInfo::kSkip,aElement,n,0);
       } else {
-         TVectorLoopConfig cached_config( cached->fClass->Size(), /* read */ kTRUE );
+         TVectorLoopConfig cached_config( nullptr, cached->fClass->Size(), /* read */ kTRUE );
          void *cached_start = (*cached)[0];
          void *cached_end = ((char*)cached_start) + cached->fSize * cached_config.fIncrement;
          config->fAction(b,cached_start,cached_end,&cached_config);
@@ -1559,7 +1619,7 @@ namespace TStreamerInfoActions
          UInt_t n = proxy->Size();
          info->ReadBufferSkip(b, *proxy,config->fCompInfo,config->fCompInfo->fType+TStreamerInfo::kSkip,aElement,n,0);
       } else {
-         TVectorLoopConfig cached_config( cached->fClass->Size(), /* read */ kTRUE );
+         TVectorLoopConfig cached_config( nullptr, cached->fClass->Size(), /* read */ kTRUE );
          void *cached_start = (*cached)[0];
          void *cached_end = ((char*)cached_start) + cached->fSize * cached_config.fIncrement;
          config->fAction(b,cached_start,cached_end,&cached_config);
@@ -3821,14 +3881,14 @@ TStreamerInfoActions::TActionSequence *TStreamerInfoActions::TActionSequence::Cr
 
       // We can speed up the iteration in case of vector.  We also know that all emulated collection are stored internally as a vector.
       Long_t increment = proxy.GetIncrement();
-      sequence->fLoopConfig = new TVectorLoopConfig(increment, /* read */ kTRUE);
+      sequence->fLoopConfig = new TVectorLoopConfig(&proxy, increment, /* read */ kTRUE);
    } else if (proxy.GetCollectionType() == ROOT::kSTLset || proxy.GetCollectionType() == ROOT::kSTLunorderedset
               || proxy.GetCollectionType() == ROOT::kSTLmultiset || proxy.GetCollectionType() == ROOT::kSTLunorderedmultiset
               || proxy.GetCollectionType() == ROOT::kSTLmap || proxy.GetCollectionType() == ROOT::kSTLmultimap
               || proxy.GetCollectionType() == ROOT::kSTLunorderedmap || proxy.GetCollectionType() == ROOT::kSTLunorderedmultimap)
    {
       Long_t increment = proxy.GetIncrement();
-      sequence->fLoopConfig = new TVectorLoopConfig(increment, /* read */ kTRUE);
+      sequence->fLoopConfig = new TVectorLoopConfig(&proxy, increment, /* read */ kTRUE);
       // sequence->fLoopConfig = new TAssocLoopConfig(proxy);
    } else {
       sequence->fLoopConfig = new TGenericLoopConfig(&proxy, /* read */ kTRUE);
@@ -3938,7 +3998,7 @@ TStreamerInfoActions::TActionSequence *TStreamerInfoActions::TActionSequence::Cr
 
          // We can speed up the iteration in case of vector.  We also know that all emulated collection are stored internally as a vector.
          Long_t increment = proxy.GetIncrement();
-         sequence->fLoopConfig = new TVectorLoopConfig(increment, /* read */ kFALSE);
+         sequence->fLoopConfig = new TVectorLoopConfig(&proxy, increment, /* read */ kFALSE);
       /*} else if (proxy.GetCollectionType() == ROOT::kSTLset || proxy.GetCollectionType() == ROOT::kSTLmultiset
                  || proxy.GetCollectionType() == ROOT::kSTLmap || proxy.GetCollectionType() == ROOT::kSTLmultimap)
       {
@@ -4111,6 +4171,83 @@ TStreamerInfoActions::TActionSequence *TStreamerInfoActions::TActionSequence::Cr
    return sequence;
 }
 
+void TStreamerInfoActions::TActionSequence::AddToSubSequence(TStreamerInfoActions::TActionSequence *sequence,
+      const TStreamerInfoActions::TIDs &element_ids,
+      Int_t offset,
+      TStreamerInfoActions::TActionSequence::SequenceGetter_t create)
+{
+   for(UInt_t id = 0; id < element_ids.size(); ++id) {
+      if ( element_ids[id].fElemID < 0 ) {
+         if (element_ids[id].fNestedIDs) {
+            auto original = create(element_ids[id].fNestedIDs->fInfo,
+                                   sequence->fLoopConfig ? sequence->fLoopConfig->GetCollectionProxy() : nullptr,
+                                   nullptr);
+            if (element_ids[id].fNestedIDs->fOnfileObject) {
+               auto conf = new TConfigurationPushDataCache(element_ids[id].fNestedIDs->fInfo, element_ids[id].fNestedIDs->fOnfileObject, offset);
+               if ( sequence->fLoopConfig )
+                  sequence->AddAction( PushDataCacheGenericCollection, conf );
+               else
+                  sequence->AddAction( PushDataCache, conf );
+            }
+
+            original->AddToSubSequence(sequence, element_ids[id].fNestedIDs->fIDs, element_ids[id].fNestedIDs->fOffset, create);
+
+            if (element_ids[id].fNestedIDs->fOnfileObject)
+               sequence->AddAction( PopDataCache,
+                  new TConfigurationPushDataCache(element_ids[id].fNestedIDs->fInfo, nullptr, element_ids[id].fNestedIDs->fOffset) );
+         } else {
+            TStreamerInfoActions::ActionContainer_t::iterator end = fActions.end();
+            for(TStreamerInfoActions::ActionContainer_t::iterator iter = fActions.begin();
+               iter != end;
+               ++iter)
+            {
+               TConfiguration *conf = iter->fConfiguration->Copy();
+               if (!iter->fConfiguration->fInfo->GetElements()->At(iter->fConfiguration->fElemId)->TestBit(TStreamerElement::kCache))
+                  conf->AddToOffset(offset);
+               sequence->AddAction( iter->fAction, conf );
+            }
+         }
+      } else {
+         int localIndex = 0;
+         TStreamerInfoActions::ActionContainer_t::iterator end = fActions.end();
+         for(TStreamerInfoActions::ActionContainer_t::iterator iter = fActions.begin();
+             iter != end;
+             ++iter) {
+            // fprintf(stderr, "With element_ids[%d] For %s comparing act[%d/%zu] %d to %d  for %p vs %p %s\n",
+            //         id,
+            //         iter->fConfiguration->fInfo->GetName(),
+            //         localIndex, fActions.size(),
+            //         iter->fConfiguration->fElemId,
+            //         (UInt_t)element_ids[id].fElemID, iter->fConfiguration->fInfo,
+            //         element_ids[id].fInfo,
+            //         element_ids[id].fInfo ? element_ids[id].fInfo->GetName() : "nullptr" );
+            ++localIndex;
+            if ( iter->fConfiguration->fElemId == (UInt_t)element_ids[id].fElemID ) {
+               TConfiguration *conf = iter->fConfiguration->Copy();
+               if (!iter->fConfiguration->fInfo->GetElements()->At(iter->fConfiguration->fElemId)->TestBit(TStreamerElement::kCache))
+                  conf->AddToOffset(offset);
+               sequence->AddAction( iter->fAction, conf );
+            }
+         }
+      }
+   }
+}
+
+TStreamerInfoActions::TActionSequence *TStreamerInfoActions::TActionSequence::CreateSubSequence(const TIDs &element_ids, size_t offset,
+      TStreamerInfoActions::TActionSequence::SequenceGetter_t create)
+{
+   // Create a sequence containing the subset of the action corresponding to the SteamerElement whose ids is contained in the vector.
+   // 'offset' is the location of this 'class' within the object (address) that will be passed to ReadBuffer when using this sequence.
+
+   TStreamerInfoActions::TActionSequence *sequence = new TStreamerInfoActions::TActionSequence(fStreamerInfo,element_ids.size());
+
+   sequence->fLoopConfig = fLoopConfig ? fLoopConfig->Copy() : 0;
+
+   AddToSubSequence(sequence, element_ids, offset, create);
+
+   return sequence;
+}
+
 TStreamerInfoActions::TActionSequence *TStreamerInfoActions::TActionSequence::CreateSubSequence(const std::vector<Int_t> &element_ids, size_t offset)
 {
    // Create a sequence containing the subset of the action corresponding to the SteamerElement whose ids is contained in the vector.
diff --git a/io/io/src/TStreamerInfoReadBuffer.cxx b/io/io/src/TStreamerInfoReadBuffer.cxx
index 17a9a0eaa5b04f58a3da795c4535d62eed7b1124..68ce0948f406428b714e7e3797ddfb9c0bb27c09 100644
--- a/io/io/src/TStreamerInfoReadBuffer.cxx
+++ b/io/io/src/TStreamerInfoReadBuffer.cxx
@@ -543,6 +543,7 @@ Int_t TStreamerInfo::ReadBufferArtificial(TBuffer &b, const T &arr,
       TVirtualArray *objarr = ((TBufferFile&)b).PeekDataCache();
       if (objarr) {
          obj.fClass = objarr->fClass;
+
          for(Int_t k=0; k<narr; ++k) {
             obj.fObject = objarr->GetObjectAt(k);
             readfunc(arr[k]+eoffset, &obj);
diff --git a/tree/tree/inc/TBranchElement.h b/tree/tree/inc/TBranchElement.h
index 501029aa12d781ff5475dcec4e6cfc0ec6039e20..994e26c99e985f89cca8b7e21b7408a8b51cdc3f 100644
--- a/tree/tree/inc/TBranchElement.h
+++ b/tree/tree/inc/TBranchElement.h
@@ -38,7 +38,11 @@ class TVirtualCollectionIterators;
 class TVirtualCollectionPtrIterators;
 class TVirtualArray;
 
-namespace TStreamerInfoActions { class TActionSequence; }
+namespace TStreamerInfoActions {
+   class TActionSequence;
+   struct TIDNode;
+   using TIDs = std::vector<TIDNode>;
+}
 
 
 class TBranchElement : public TBranch {
@@ -90,8 +94,9 @@ protected:
    TStreamerInfo           *fInfo;          ///<! Pointer to StreamerInfo
    char                    *fObject;        ///<! Pointer to object at *fAddress
    TVirtualArray           *fOnfileObject;  ///<! Place holder for the onfile representation of data members.
-   Bool_t                   fInit;          ///<! Initialization flag for branch assignment
-   Bool_t                   fInitOffsets;   ///<! Initialization flag to not endlessly recalculate offsets
+   Bool_t                   fInit : 1;      ///<! Initialization flag for branch assignment
+   Bool_t                   fInInitInfo : 1;///<! True during the 2nd part of InitInfo (cut recursion).
+   Bool_t                   fInitOffsets: 1;///<! Initialization flag to not endlessly recalculate offsets
    TClassRef                fTargetClass;   ///<! Reference to the target in-memory class
    TClassRef                fCurrentClass;  ///<! Reference to current (transient) class definition
    TClassRef                fParentClass;   ///<! Reference to class definition in fParentName
@@ -100,6 +105,7 @@ protected:
    Int_t                   *fBranchOffset;  ///<! Sub-Branch offsets with respect to current transient class
    Int_t                    fBranchID;      ///<! ID number assigned by a TRefTable.
    std::vector<Int_t>       fIDs;           ///<! List of the serial number of all the StreamerInfo to be used.
+   TStreamerInfoActions::TIDs fNewIDs; ///<! Nested List of the serial number of all the StreamerInfo to be used.
    TStreamerInfoActions::TActionSequence *fReadActionSequence;  ///<! Set of actions to be executed to extract the data from the basket.
    TStreamerInfoActions::TActionSequence *fFillActionSequence;  ///<! Set of actions to be executed to write the data to the basket.
    TVirtualCollectionIterators           *fIterators;      ///<! holds the iterators when the branch is of fType==4.
@@ -119,9 +125,11 @@ protected:
    virtual void             InitializeOffsets();
    virtual void             InitInfo();
    Bool_t                   IsMissingCollection() const;
+   TStreamerInfo           *FindOnfileInfo(TClass *valueClass, const TObjArray &branches) const;
    TClass                  *GetParentClass(); // Class referenced by fParentName
    TStreamerInfo           *GetInfoImp() const;
    void                     ReleaseObject();
+   void                     SetupInfo();
    void                     SetBranchCount(TBranchElement* bre);
    void                     SetBranchCount2(TBranchElement* bre) { fBranchCount2 = bre; }
    Int_t                    Unroll(const char* name, TClass* cltop, TClass* cl, char* ptr, Int_t basketsize, Int_t splitlevel, Int_t btype);
diff --git a/tree/tree/src/TBranchElement.cxx b/tree/tree/src/TBranchElement.cxx
index e0a850c92319e4f94e7410360cb741205ef9d0f9..51a023b63c7e3d565c5cdb85756648e7e27ede38 100644
--- a/tree/tree/src/TBranchElement.cxx
+++ b/tree/tree/src/TBranchElement.cxx
@@ -148,6 +148,7 @@ TBranchElement::TBranchElement()
 , fObject(0)
 , fOnfileObject(0)
 , fInit(kFALSE)
+, fInInitInfo(kFALSE)
 , fInitOffsets(kFALSE)
 , fTargetClass()
 , fCurrentClass()
@@ -192,6 +193,7 @@ TBranchElement::TBranchElement(TTree *tree, const char* bname, TStreamerInfo* si
 , fObject(0)
 , fOnfileObject(0)
 , fInit(kTRUE)
+, fInInitInfo(kFALSE)
 , fInitOffsets(kFALSE)
 , fTargetClass(fClassName)
 , fCurrentClass()
@@ -234,6 +236,7 @@ TBranchElement::TBranchElement(TBranch *parent, const char* bname, TStreamerInfo
 , fObject(0)
 , fOnfileObject(0)
 , fInit(kTRUE)
+, fInInitInfo(kFALSE)
 , fInitOffsets(kFALSE)
 , fTargetClass( fClassName )
 , fCurrentClass()
@@ -646,6 +649,9 @@ TBranchElement::TBranchElement(TTree *tree, const char* bname, TClonesArray* clo
 , fClassName("TClonesArray")
 , fParentName()
 , fInfo((TStreamerInfo*)TClonesArray::Class()->GetStreamerInfo())
+, fInit(kTRUE)
+, fInInitInfo(kFALSE)
+, fInitOffsets(kFALSE)
 , fTargetClass( fClassName )
 , fCurrentClass()
 , fParentClass()
@@ -670,6 +676,9 @@ TBranchElement::TBranchElement(TBranch *parent, const char* bname, TClonesArray*
 , fClassName("TClonesArray")
 , fParentName()
 , fInfo((TStreamerInfo*)TClonesArray::Class()->GetStreamerInfo())
+, fInit(kTRUE)
+, fInInitInfo(kFALSE)
+, fInitOffsets(kFALSE)
 , fTargetClass( fClassName )
 , fCurrentClass()
 , fParentClass()
@@ -789,6 +798,9 @@ TBranchElement::TBranchElement(TTree *tree, const char* bname, TVirtualCollectio
 : TBranch()
 , fClassName(cont->GetCollectionClass()->GetName())
 , fParentName()
+, fInit(kTRUE)
+, fInInitInfo(kFALSE)
+, fInitOffsets(kFALSE)
 , fTargetClass( fClassName )
 , fCurrentClass()
 , fParentClass()
@@ -812,6 +824,9 @@ TBranchElement::TBranchElement(TBranch *parent, const char* bname, TVirtualColle
 : TBranch()
 , fClassName(cont->GetCollectionClass()->GetName())
 , fParentName()
+, fInit(kTRUE)
+, fInInitInfo(kFALSE)
+, fInitOffsets(kFALSE)
 , fTargetClass( fClassName )
 , fCurrentClass()
 , fParentClass()
@@ -1883,94 +1898,209 @@ char* TBranchElement::GetAddress() const
    return fAddress;
 }
 
-////////////////////////////////////////////////////////////////////////////////
-/// Init the streamer info for the branch class, try to compensate for class
-/// code unload/reload and schema evolution.
 
-void TBranchElement::InitInfo()
+// For a mother branch of type 3 or 4, find the 'correct' StreamerInfo for the
+// content of the collection by find a sub-branch corresponding to a direct data member
+// of the containee class (valueClass)
+// Default to the current StreamerInfo if none are found.
+TStreamerInfo *TBranchElement::FindOnfileInfo(TClass *valueClass, const TObjArray &branches) const
 {
-   if (!fInfo) {
-      // We did not already have streamer info, so now we must find it.
-      TClass* cl = fBranchClass.GetClass();
+   TStreamerInfo *localInfo = nullptr;
+
+   // Search for the correct version.
+   for(auto subbe : TRangeDynCast<TBranchElement>( branches )) {
+      if (!subbe->fInfo)
+         subbe->SetupInfo();
+      if (valueClass == subbe->fInfo->GetClass()) { // Use GetInfo to provoke its creation.
+         localInfo = subbe->fInfo;
+         break;
+      }
+   }
+   if (!localInfo) {
+      // This is likely sub-optimal as we really should call GetFile but it is non-const.
+      auto file = fDirectory ? fDirectory->GetFile() : nullptr;
+      if (file && file->GetSeekInfo()) {
+         localInfo = (TStreamerInfo*)file->GetStreamerInfoCache()->FindObject(valueClass->GetName());
+         if (localInfo) {
+            if (valueClass->IsVersioned()) {
+               localInfo = (TStreamerInfo*)valueClass->GetStreamerInfo(localInfo->GetClassVersion());
+            } else {
+               localInfo = (TStreamerInfo*)valueClass->FindStreamerInfo(localInfo->GetCheckSum());
+               if (localInfo) {
+                  // Now that we found it, we need to make sure it is initialize (Find does not initialize the StreamerInfo).
+                  localInfo = (TStreamerInfo*)valueClass->GetStreamerInfo(localInfo->GetClassVersion());
+               }
+            }
+         }
+      }
+   }
+   if (!localInfo)
+      localInfo = (TStreamerInfo*)valueClass->GetStreamerInfo();
+   return localInfo;
+}
 
-      //------------------------------------------------------------------------
-      // Check if we're dealing with the name change
-      //////////////////////////////////////////////////////////////////////////
+namespace {
+   static void GatherArtificialElements(std::vector<int> &fIDs, const TObjArray &branches, TStreamerInfoActions::TIDs &ids, TString prefix, TStreamerInfo *info, Int_t offset) {
+   size_t ndata = info->GetNelement();
+   for (size_t i =0; i < ndata; ++i) {
+      TStreamerElement *nextel = info->GetElement(i);
 
-      TClass* targetClass = 0;
-      if( fTargetClass.GetClassName()[0] ) {
-         targetClass = fTargetClass;
-         if (!targetClass && GetCollectionProxy()) {
-            // We are in the case where the branch holds a custom collection
-            // proxy but the dictionary is not loaded, calling
-            // GetCollectionProxy had the side effect of creating the TClass
-            // corresponding to this emulated collection.
-            targetClass = fTargetClass;
-         }
-         if ( !targetClass ) {
-            Error( "InitInfo", "The target class dictionary is not present!" );
-            return;
-         }
-      } else {
-         targetClass = cl;
+      if (nextel->GetType() == TStreamerInfo::kCacheDelete
+         || nextel->GetType() == TStreamerInfo::kCacheNew) {
+         continue;
       }
-      if (cl) {
-         //---------------------------------------------------------------------
-         // Get the streamer info for given version
-         ///////////////////////////////////////////////////////////////////////
 
-         {
-            if ( (cl->Property() & kIsAbstract) && cl == targetClass) {
-               TBranchElement *parent = (TBranchElement*)GetMother()->GetSubBranch(this);
-               if (parent && parent != this && !parent->GetClass()->IsLoaded() ) {
-                  // Our parent's class is emulated and we represent an abstract class.
-                  // and the target class has not been set explicilty.
-                  TString target = cl->GetName();
-                  target += "@@emulated";
-                  fTargetClass.SetName(target);
-
-                  if (!fTargetClass) {
-                     cl->GetStreamerInfoAbstractEmulated(fClassVersion);
-                  }
-                  targetClass = fTargetClass;
-               }
+      TString ename =  prefix + nextel->GetName();
+
+      if (ename[0]=='*')
+         ename.Remove(0,1);
+
+      if (nextel->IsA() == TStreamerArtificial::Class()
+         && branches.FindObject(ename) == nullptr) {
+
+         fIDs.push_back(i);
+         ids.push_back(i);
+         ids.back().fElement = nextel;
+         ids.back().fInfo = info;
+      }
+
+      if (nextel->CannotSplit())
+         continue;
+
+      TClass *elementClass = nextel->GetClassPointer();
+      TBranchElement *be = (TBranchElement*)branches.FindObject(ename);
+      if (elementClass && (!be || be->GetType() == -2)) {
+         TStreamerInfo *nextinfo = nullptr;
+
+         // nextinfo_version = ....
+         auto search = be ? be->GetListOfBranches() : &branches;
+         TVirtualArray *onfileObject = nullptr;
+         for(auto subbe : TRangeDynCast<TBranchElement>( *search )) {
+
+            if (elementClass == subbe->GetInfo()->GetClass()) { // Use GetInfo to provoke its creation.
+               nextinfo = subbe->GetInfo();
+               onfileObject = subbe->GetOnfileObject();
+               break;
             }
-            if( targetClass != cl ) {
-               fInfo = (TStreamerInfo*)targetClass->GetConversionStreamerInfo( cl, fClassVersion );
-            } else {
-               fInfo = (TStreamerInfo*)cl->GetStreamerInfo(fClassVersion);
+         }
+         if (!nextinfo) {
+            nextinfo = (TStreamerInfo *)elementClass->GetStreamerInfo();
+            if (elementClass->GetCollectionProxy() && elementClass->GetCollectionProxy()->GetValueClass()) {
+               nextinfo = (TStreamerInfo *)elementClass->GetCollectionProxy()->GetValueClass()->GetStreamerInfo(); // NOTE: need to find the right version
             }
          }
+         ids.emplace_back(nextinfo, offset + nextel->GetOffset());
+         std::vector<int> subids; // ignored
+         ids.back().fNestedIDs->fOnfileObject = onfileObject;
+         GatherArtificialElements(subids, branches, ids.back().fNestedIDs->fIDs, ename + ".", nextinfo, offset + nextel->GetOffset());
+         if (ids.back().fNestedIDs->fIDs.empty())
+            ids.pop_back();
+      }
+   }
+};
+} // Anonymous namespace.
 
-         // FIXME: Check that the found streamer info checksum matches our branch class checksum here.
-         // Check to see if the class code was unloaded/reloaded
-         // since we were created.
-         R__LOCKGUARD(gInterpreterMutex);
-         if (fCheckSum && (cl->IsForeign() || (!cl->IsLoaded() && (fClassVersion == 1) && cl->GetStreamerInfos()->At(1) && (fCheckSum != ((TVirtualStreamerInfo*) cl->GetStreamerInfos()->At(1))->GetCheckSum())))) {
-            // Try to compensate for a class that got unloaded on us.
-            // Search through the streamer infos by checksum
-            // and take the first match.
-
-            TStreamerInfo* info;
-            if( targetClass != cl )
-               info = (TStreamerInfo*)targetClass->GetConversionStreamerInfo( cl, fCheckSum );
-            else {
-               info = (TStreamerInfo*)cl->FindStreamerInfo( fCheckSum );
-               if (info) {
-                  // Now that we found it, we need to make sure it is initialize (Find does not initialize the StreamerInfo).
-                  info = (TStreamerInfo*)cl->GetStreamerInfo(info->GetClassVersion());
+
+////////////////////////////////////////////////////////////////////////////////
+/// Set the value of fInfo.  This is part one of InitInfo.
+/// To be used as:
+/// if (!fInfo)
+///   SetupInfo();
+/// It would only be used within InitInfo (and its callees)
+
+void TBranchElement::SetupInfo()
+{
+   // We did not already have streamer info, so now we must find it.
+   TClass* cl = fBranchClass.GetClass();
+
+   //------------------------------------------------------------------------
+   // Check if we're dealing with the name change
+   //////////////////////////////////////////////////////////////////////////
+
+   TClass* targetClass = 0;
+   if( fTargetClass.GetClassName()[0] ) {
+      targetClass = fTargetClass;
+      if (!targetClass && GetCollectionProxy()) {
+         // We are in the case where the branch holds a custom collection
+         // proxy but the dictionary is not loaded, calling
+         // GetCollectionProxy had the side effect of creating the TClass
+         // corresponding to this emulated collection.
+         targetClass = fTargetClass;
+      }
+      if ( !targetClass ) {
+         Error( "InitInfo", "The target class dictionary is not present!" );
+         return;
+      }
+   } else {
+      targetClass = cl;
+   }
+   if (cl) {
+      //---------------------------------------------------------------------
+      // Get the streamer info for given version
+      ///////////////////////////////////////////////////////////////////////
+
+      {
+         if ( (cl->Property() & kIsAbstract) && cl == targetClass) {
+            TBranchElement *parent = (TBranchElement*)GetMother()->GetSubBranch(this);
+            if (parent && parent != this && !parent->GetClass()->IsLoaded() ) {
+               // Our parent's class is emulated and we represent an abstract class.
+               // and the target class has not been set explicilty.
+               TString target = cl->GetName();
+               target += "@@emulated";
+               fTargetClass.SetName(target);
+
+               if (!fTargetClass) {
+                  cl->GetStreamerInfoAbstractEmulated(fClassVersion);
                }
+               targetClass = fTargetClass;
             }
-            if( info ) {
-               fInfo = info;
-               // We no longer reset the class version so that in case the user is passing us later
-               // the address of a class that require (another) Conversion we can find the proper
-               // StreamerInfo.
-               //    fClassVersion = fInfo->GetClassVersion();
+         }
+         if( targetClass != cl ) {
+            fInfo = (TStreamerInfo*)targetClass->GetConversionStreamerInfo( cl, fClassVersion );
+         } else {
+            fInfo = (TStreamerInfo*)cl->GetStreamerInfo(fClassVersion);
+         }
+      }
+
+      // FIXME: Check that the found streamer info checksum matches our branch class checksum here.
+      // Check to see if the class code was unloaded/reloaded
+      // since we were created.
+      R__LOCKGUARD(gInterpreterMutex);
+      if (fCheckSum && (cl->IsForeign() || (!cl->IsLoaded() && (fClassVersion == 1) && cl->GetStreamerInfos()->At(1) && (fCheckSum != ((TVirtualStreamerInfo*) cl->GetStreamerInfos()->At(1))->GetCheckSum())))) {
+         // Try to compensate for a class that got unloaded on us.
+         // Search through the streamer infos by checksum
+         // and take the first match.
+
+         TStreamerInfo* info;
+         if( targetClass != cl )
+            info = (TStreamerInfo*)targetClass->GetConversionStreamerInfo( cl, fCheckSum );
+         else {
+            info = (TStreamerInfo*)cl->FindStreamerInfo( fCheckSum );
+            if (info) {
+               // Now that we found it, we need to make sure it is initialize (Find does not initialize the StreamerInfo).
+               info = (TStreamerInfo*)cl->GetStreamerInfo(info->GetClassVersion());
             }
          }
+         if( info ) {
+            fInfo = info;
+            // We no longer reset the class version so that in case the user is passing us later
+            // the address of a class that require (another) Conversion we can find the proper
+            // StreamerInfo.
+            //    fClassVersion = fInfo->GetClassVersion();
+         }
       }
    }
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+/// Init the streamer info for the branch class, try to compensate for class
+/// code unload/reload and schema evolution.
+
+void TBranchElement::InitInfo()
+{
+   if (!fInfo)
+      SetupInfo();
 
    //
    //  Fixup cached streamer info if necessary.
@@ -1984,6 +2114,10 @@ void TBranchElement::InitInfo()
 
          Error("InitInfo","StreamerInfo is not compiled.");
       }
+      // return immediately if we are called recursively.
+      if (fInInitInfo)
+         return;
+      fInInitInfo = kTRUE;
       if (!fInit) {
          // We were read in from a file, figure out what our fID should be,
          // schema evolution must be considered.
@@ -2005,6 +2139,7 @@ void TBranchElement::InitInfo()
             if (elt && offset!=TStreamerInfo::kMissing) {
                size_t ndata = fInfo->GetNelement();
                fIDs.clear();
+               fNewIDs.clear();
                for (size_t i = 0; i < ndata; ++i) {
                   if (fInfo->GetElement(i) == elt) {
                      if (elt->TestBit (TStreamerElement::kCache)
@@ -2017,10 +2152,18 @@ void TBranchElement::InitInfo()
                         // ReadLeaves).
                         // fID = i+1;
                         fID = i;
-                        if (elt->TestBit(TStreamerElement::kRepeat)) {
-                           fIDs.push_back(fID+1);
-                        } else if (fInfo->GetElement(i+1)->TestBit(TStreamerElement::kWrite)) {
-                           fIDs.push_back(fID+1);
+                        if (fType != 2) {
+                           if (elt->TestBit(TStreamerElement::kRepeat)) {
+                              fIDs.push_back(fID+1);
+                              fNewIDs.push_back(fID+1);
+                              fNewIDs.back().fElement = fInfo->GetElement(i+1);
+                              fNewIDs.back().fInfo = fInfo;
+                           } else if (fInfo->GetElement(i+1)->TestBit(TStreamerElement::kWrite)) {
+                              fIDs.push_back(fID+1);
+                              fNewIDs.push_back(fID+1);
+                              fNewIDs.back().fElement = fInfo->GetElement(i+1);
+                              fNewIDs.back().fInfo = fInfo;
+                           }
                         }
                      } else {
                         fID = i;
@@ -2033,6 +2176,11 @@ void TBranchElement::InitInfo()
                }
                for (size_t i = fID+1+(fIDs.size()); i < ndata; ++i) {
                   TStreamerElement *nextel = fInfo->GetElement(i);
+
+                  if (s != nextel->GetName()) {
+                     // We moved on to the next set
+                     break;
+                  }
                   // Add all (and only) the Artificial Elements that follows this StreamerInfo.
                   // fprintf(stderr,"%s/%d[%zu] passing trhough %zu %s\n",GetName(),fID,fIDs.size(),i,nextel->GetName());
                   if (fType==31||fType==41) {
@@ -2052,16 +2200,20 @@ void TBranchElement::InitInfo()
                   }
                   if (nextel->IsA() != TStreamerArtificial::Class()
                       || nextel->GetType() == TStreamerInfo::kCacheDelete ) {
-                     break;
+                     continue;
                   }
                   // NOTE: We should verify that the rule's source are 'before'
                   // or 'at' this branch.
                   // fprintf(stderr,"%s/%d[%zu] pushd %zu %s\n",GetName(),fID,fIDs.size(),i,nextel->GetName());
                   fIDs.push_back(i);
+                  fNewIDs.push_back(i);
+                  fNewIDs.back().fElement = nextel;
+                  fNewIDs.back().fInfo = fInfo;
                }
             } else if (elt && offset==TStreamerInfo::kMissing) {
                // Still re-assign fID properly.
                fIDs.clear();
+               fNewIDs.clear();
                size_t ndata = fInfo->GetNelement();
                for (size_t i = 0; i < ndata; ++i) {
                   if (fInfo->GetElement(i) == elt) {
@@ -2072,6 +2224,7 @@ void TBranchElement::InitInfo()
             } else {
                // We have not even found the element .. this is strange :(
                // fIDs.clear();
+               // fNewIDs.clear();
                // fID = -3;
                // SetBit(kDoNotProcess);
             }
@@ -2100,6 +2253,30 @@ void TBranchElement::InitInfo()
                lastbranch->SetBit(kOwnOnfileObj);
             }
          }
+         if (fType == 3 || fType == 4 || (fType == 0 && fID == -2)) {
+            // Need to add the rule targetting transient members.
+            TStreamerInfo *localInfo = fInfo;
+            if (fType == 3 || fType == 4) {
+               // Don't we have real version information?
+               // Not unless there is a subbranch with a non-split element of the class.
+               // Search for the correct version.
+               localInfo = FindOnfileInfo(fClonesClass, fBranches);
+            }
+
+            TString prefix(GetName());
+            if (prefix[prefix.Length()-1] != '.') {
+               if (fType == 3 || fType == 4) {
+                  prefix += ".";
+               } else {
+                  prefix = "";
+               }
+            }
+            fIDs.clear();
+            fNewIDs.clear();
+
+            GatherArtificialElements(fIDs, fBranches, fNewIDs, prefix, localInfo, 0);
+
+         }
          fInit = kTRUE;
 
          // Get the action sequence we need to copy for reading.
@@ -2112,6 +2289,7 @@ void TBranchElement::InitInfo()
       }
       SetReadLeavesPtr();
       SetFillLeavesPtr();
+      fInInitInfo = kFALSE;
    }
 }
 
@@ -2320,6 +2498,45 @@ Int_t TBranchElement::GetEntry(Long64_t entry, Int_t getall)
             }
             break;
       }
+      if (!TestBit(kDecomposedObj) && fReadActionSequence && !fReadActionSequence->fActions.empty()) {
+         if (fType == 3) {
+            // Apply the unattached rules; by definition they do not need any
+            // input from a buffer.
+            TBufferFile b(TBufferFile::kRead, 1);
+
+            auto ndata = GetNdata();
+
+            TClonesArray* clones = (TClonesArray*) fObject;
+            if (clones->IsZombie()) {
+               return -1;
+            }
+            R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,ndata);
+
+            char **arr = (char **)clones->GetObjectRef();
+            char **end = arr + fNdata;
+
+           b.ApplySequenceVecPtr(*fReadActionSequence,arr,end);
+         } else if (fType == 4) {
+            // Apply the unattached rules; by definition they do not need any
+            // input from a buffer.
+            TBufferFile b(TBufferFile::kRead, 1);
+
+            auto ndata = GetNdata();
+
+            R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,ndata);
+            TVirtualCollectionProxy *proxy = GetCollectionProxy();
+            TVirtualCollectionProxy::TPushPop helper(proxy, fObject);
+
+            TVirtualCollectionIterators *iter = fIterators;
+            b.ApplySequence(*fReadActionSequence,iter->fBegin,iter->fEnd);
+         } else {
+            // Apply the unattached rules; by definition they do not need any
+            // input from a buffer.
+            TBufferFile b(TBufferFile::kRead, 1);
+            R__PushCache onfileObject(((TBufferFile&)b),fOnfileObject,fNdata);
+            b.ApplySequence(*fReadActionSequence, fObject);
+         }
+      }
    } else {
       // -- Terminal branch.
       if (fBranchCount && (fBranchCount->GetReadEntry() != entry)) {
@@ -3263,6 +3480,15 @@ void TBranchElement::InitializeOffsets()
          }
       }
    }
+   const bool isSplitNode = (fType == 2 || fType == 1 || (fType == 0 && fID == -2)) && !fBranches.IsEmpty();
+   if (fReadActionSequence && isSplitNode) {
+      TBranchElement *parent = dynamic_cast<TBranchElement*>(GetMother()->GetSubBranch(this));
+      auto index = parent->fBranches.IndexOf(this);
+      if (index >= 0) {
+         fReadActionSequence->AddToOffset( - parent->fBranchOffset[index] );
+      }
+   }
+
    fInitOffsets = kTRUE;
 }
 
@@ -3327,6 +3553,19 @@ Bool_t TBranchElement::IsMissingCollection() const
 ////////////////////////////////////////////////////////////////////////////////
 /// Print branch parameters.
 
+static void PrintElements(const TStreamerInfo *info, const TStreamerInfoActions::TIDs &ids)
+{
+   for(auto &cursor : ids) {
+      auto id = cursor.fElemID;
+      if (id >= 0)
+         info->GetElement(id)->ls();
+      else if (cursor.fNestedIDs) {
+         Printf("      With subobject of type %s offset = %d", cursor.fNestedIDs->fInfo->GetName(), cursor.fNestedIDs->fOffset);
+         PrintElements(cursor.fNestedIDs->fInfo, cursor.fNestedIDs->fIDs);
+      }
+   }
+}
+
 void TBranchElement::Print(Option_t* option) const
 {
    Int_t nbranches = fBranches.GetEntriesFast();
@@ -3356,9 +3595,30 @@ void TBranchElement::Print(Option_t* option) const
    if (strncmp(option,"debugInfo",strlen("debugInfo"))==0)  {
       Printf("Branch %s uses:",GetName());
       if (fID>=0) {
-         GetInfoImp()->GetElement(fID)->ls();
+         // GetInfoImp()->GetElement(fID)->ls();
+         // for(UInt_t i=0; i< fIDs.size(); ++i) {
+         //    GetInfoImp()->GetElement(fIDs[i])->ls();
+         // }
+         TStreamerInfo *localInfo = GetInfoImp();
+         if (fType == 3 || fType == 4) {
+            // Search for the correct version.
+            localInfo = FindOnfileInfo(fClonesClass, fBranches);
+         }
+         Printf("   With new ids:");
+         if (fType != 3 && fType != 4)
+            localInfo->GetElement(fID)->ls();
+         PrintElements(localInfo, fNewIDs);
+         Printf("   with read actions:");
+         if (fReadActionSequence) fReadActionSequence->Print(option);
+         Printf("   with write actions:");
+         if (fFillActionSequence) fFillActionSequence->Print(option);
+      } else if (!fIDs.empty() && GetInfoImp()) {
+         TVirtualStreamerInfo *info = GetInfoImp();
+         if (fType == 3 || fType == 4) {
+            info = fClonesClass->GetStreamerInfo();
+         }
          for(UInt_t i=0; i< fIDs.size(); ++i) {
-            GetInfoImp()->GetElement(fIDs[i])->ls();
+            info->GetElement(fIDs[i])->ls();
          }
          Printf("   with read actions:");
          if (fReadActionSequence) fReadActionSequence->Print(option);
@@ -5038,6 +5298,56 @@ void TBranchElement::SetOffset(Int_t offset)
 ////////////////////////////////////////////////////////////////////////////////
 /// Set the sequence of actions needed to read the data out of the buffer.
 
+#if 0
+// Maybe owner unique_ptr
+struct SequencePtr {
+   TStreamerInfoActions::TActionSequence *fSequence = nullptr;
+   Bool_t fOwner = kFALSE;
+
+   ~SequencePtr() {
+      if (fOwner) delete fSequence;
+   }
+
+   // Accessor to the pointee.
+   TStreamerInfoActions::TActionSequence &operator*() const {
+      return *fSequence;
+   }
+
+   // Accessor to the pointee
+   TStreamerInfoActions::TActionSequence *operator->() const {
+      return fSequence;
+   }
+
+   // Return true is the pointee is not nullptr.
+   Bool_t operator bool() {
+      return fSequence != nullptr;
+   }
+};
+
+SequencePtr ReadMemberWiseActionsCollectionGetter(TVirtualStreamerInfo *info, TVirtualCollection *collectionProxy, TClass *originalClass) {
+   auto seq = info->GetReadMemberWiseActions(kTRUE);
+   return {seq, kFALSE};
+}
+SequencePtr ConversionReadMemberWiseActionsCollectionGetter(TVirtualStreamerInfo *info, TVirtualCollection *collectionProxy, TClass *originalClass) {
+   auto seq = collectionProxy->GetConversionReadMemberWiseActions(originalClass, info->GetClassVersion());
+   return {seq, kFALSE};
+}
+SequencePtr ReadMemberWiseActionsViaProxyGetter(TVirtualStreamerInfo *info, TVirtualCollection *collectionProxy, TClass *originalClass) {
+   auto seq = collectionProxy->GetReadMemberWiseActions(info->GetClassVersion());
+   return {seq, kFALSE};
+}
+SequencePtr ReadMemberWiseActionsCollectionCreator(TVirtualStreamerInfo *info, TVirtualCollection *collectionProxy, TClass *originalClass) {
+   auto seq = TStreamerInfoActions::TActionSequence::CreateReadMemberWiseActions(info,*collectionProxy);
+   return {seq, kTRUE};
+}
+// Creator5() = Creator1;
+SequencePtr ReadMemberWiseActionsGetter(TVirtualStreamerInfo *info, TVirtualCollection *collectionProxy, TClass *originalClass) {
+   auto seq = info->GetReadMemberWiseActions(kFALSE);
+   return {seq, kFALSE};
+}
+// Creator7() = Creator4
+#endif
+
 void TBranchElement::SetReadActionSequence()
 {
    if (fInfo == 0) {
@@ -5046,6 +5356,7 @@ void TBranchElement::SetReadActionSequence()
    }
 
    // Get the action sequence we need to copy for reading.
+#if 0
    TStreamerInfoActions::TActionSequence *original = 0;
    TStreamerInfoActions::TActionSequence *transient = 0;
    if (fType == 41) {
@@ -5071,14 +5382,105 @@ void TBranchElement::SetReadActionSequence()
    } else if (0<=fType && fType<=2) {
       // Note: this still requires the ObjectWise sequence to not be optimized!
       original = fInfo->GetReadMemberWiseActions(kFALSE);
+   } else if ( (fType == 3 || fType == 4) && !fIDs.empty()) {
+      auto localInfo = (TStreamerInfo*)fClonesClass->GetStreamerInfo();
+      // original = localInfo->GetReadMemberWiseActions(kTRUE);
+      original = TStreamerInfoActions::TActionSequence::CreateReadMemberWiseActions(localInfo, *GetCollectionProxy());
    }
    if (original) {
-      fIDs.insert(fIDs.begin(),fID); // Include the main element in the sequence.
+      // A 'split' node does not store data itself (it has not associated baskets)
+      const bool isSplitNode = (fType == 3 || fType == 4 || fType == 2 || (fType == 0 && fID == -2));
+      if (!isSplitNode)
+         fIDs.insert(fIDs.begin(),fID); // Include the main element in the sequence.
       if (fReadActionSequence) delete fReadActionSequence;
       fReadActionSequence = original->CreateSubSequence(fIDs,fOffset);
-      fIDs.erase(fIDs.begin());
+      if (!isSplitNode)
+         fIDs.erase(fIDs.begin());
+      else {
+         // fObject has the address of the sub-object but the streamer action have
+         // offset relative to the parent.
+         TBranchElement *parent = dynamic_cast<TBranchElement*>(GetMother()->GetSubBranch(this));
+         if (fInitOffsets) {
+            auto index = parent->fBranches.IndexOf(this);
+            if (index >= 0) {
+               fReadActionSequence->AddToOffset( - parent->fBranchOffset[index] );
+               fprintf(stderr, "Adjust %d\n", - parent->fBranchOffset[index] );
+            }
+         } // else it will be done by InitOffsets
+      }
    }
    delete transient;
+#else
+   TStreamerInfoActions::TActionSequence::SequenceGetter_t create = nullptr;
+   TClass *originalClass = nullptr;
+   TStreamerInfo *localInfo = fInfo;
+   if (fType == 41) {
+      if( fSplitLevel >= TTree::kSplitCollectionOfPointers && fBranchCount->fSTLtype == ROOT::kSTLvector) {
+         create = TStreamerInfoActions::TActionSequence::ReadMemberWiseActionsCollectionGetter;
+      } else {
+         TVirtualStreamerInfo *info = GetInfoImp();
+         if (GetParentClass() == info->GetClass()) {
+            if( fTargetClass.GetClassName()[0] && fBranchClass != fTargetClass ) {
+               originalClass = fBranchClass;
+               create = TStreamerInfoActions::TActionSequence::ConversionReadMemberWiseActionsViaProxyGetter;
+            } else {
+               create = TStreamerInfoActions::TActionSequence::ReadMemberWiseActionsViaProxyGetter;
+            }
+         } else if (GetCollectionProxy()) {
+            // Base class and embedded objects.
+            create = TStreamerInfoActions::TActionSequence::ReadMemberWiseActionsCollectionCreator;
+         }
+      }
+   } else if (fType == 31) {
+      create = TStreamerInfoActions::TActionSequence::ReadMemberWiseActionsCollectionGetter;
+   } else if (0<=fType && fType<=2) {
+      // Note: this still requires the ObjectWise sequence to not be optimized!
+      create = TStreamerInfoActions::TActionSequence::ReadMemberWiseActionsGetter;
+   } else if ( fType == 4 && !fNewIDs.empty()) {
+      localInfo = FindOnfileInfo(fClonesClass, fBranches);
+      create = TStreamerInfoActions::TActionSequence::ReadMemberWiseActionsCollectionCreator;
+   } else if ( fType == 3 && !fNewIDs.empty()) {
+      localInfo = FindOnfileInfo(fClonesClass, fBranches);
+      create = TStreamerInfoActions::TActionSequence::ReadMemberWiseActionsCollectionGetter;
+   }
+
+   if (create) {
+      // A 'split' node does not store data itself (it has not associated baskets)
+      const bool isSplitNode = (fType == 3 || fType == 4 || fType == 2 || fType == 1 || (fType == 0 && fID == -2)) && !fBranches.IsEmpty();
+
+      if (!isSplitNode) {
+         fNewIDs.insert(fNewIDs.begin(),fID); // Include the main element in the sequence.
+      }
+      if (!isSplitNode)
+         fIDs.insert(fIDs.begin(),fID); // Include the main element in the sequence.
+
+      if (fReadActionSequence) delete fReadActionSequence;
+      auto original = create(localInfo, GetCollectionProxy(), originalClass);
+
+      TStreamerInfoActions::TIDs element_ids;
+      for(auto i : fIDs) {
+         element_ids.push_back(i);
+      }
+      fReadActionSequence = original->CreateSubSequence(fNewIDs, fOffset, create);
+
+      if (!isSplitNode)
+         fNewIDs.erase(fNewIDs.begin());
+      if (!isSplitNode)
+         fIDs.erase(fIDs.begin());
+      else {
+         // fObject has the address of the sub-object but the streamer action have
+         // offset relative to the parent.
+         TBranchElement *parent = dynamic_cast<TBranchElement*>(GetMother()->GetSubBranch(this));
+         if (fInitOffsets) {
+            auto index = parent->fBranches.IndexOf(this);
+            if (index >= 0) {
+               fReadActionSequence->AddToOffset( - parent->fBranchOffset[index] );
+            }
+         } // else it will be done by InitOffsets
+      }
+   }
+#endif
+
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -5171,10 +5573,20 @@ void TBranchElement::SetFillActionSequence()
       original = fInfo->GetWriteMemberWiseActions(kFALSE);
    }
    if (original) {
-      fIDs.insert(fIDs.begin(),fID); // Include the main element in the sequence.
+      // A 'split' node does not store data itself (it has not associated baskets)
+      const bool isSplitNode = (fType == 2 || (fType == 0 && fID == -2));
+      if (!isSplitNode)
+         fIDs.insert(fIDs.begin(),fID); // Include the main element in the sequence.
       if (fFillActionSequence) delete fFillActionSequence;
       fFillActionSequence = original->CreateSubSequence(fIDs,fOffset);
-      fIDs.erase(fIDs.begin());
+      if (!isSplitNode)
+         fIDs.erase(fIDs.begin());
+      else {
+         // fObject has the address of the sub-object but the streamer action have
+         // offset relative to the parent.
+         TBranchElement *parent = dynamic_cast<TBranchElement*>(GetMother()->GetSubBranch(this));
+         fFillActionSequence->AddToOffset( -( ((char*)fObject) - ((char*)parent->fObject) ) );
+      }
    }
    delete transient;
 
@@ -5356,6 +5768,7 @@ void TBranchElement::Streamer(TBuffer& R__b)
          fLeaves.Add(leaf);
          fTree->GetListOfLeaves()->Add(leaf);
       }
+
       // SetReadLeavesPtr();
    }
    else {