diff --git a/tree/forest/v7/inc/ROOT/RColumn.hxx b/tree/forest/v7/inc/ROOT/RColumn.hxx
index 4b7cc3977982e065c41e674b55dd7607db7bd11f..96348858aed9e6b1e8dc857b1924581826e60cc9 100644
--- a/tree/forest/v7/inc/ROOT/RColumn.hxx
+++ b/tree/forest/v7/inc/ROOT/RColumn.hxx
@@ -149,10 +149,10 @@ public:
 
    /// For offset columns only, do index arithmetic from cluster-local to global indizes
    void GetCollectionInfo(const ForestSize_t index, ForestSize_t* collectionStart, ClusterSize_t* collectionSize) {
-      ForestSize_t dummy;
-      RColumnElement<ForestSize_t, EColumnType::kIndex> fElemDummy(&dummy);
-      auto idxStart = (index == 0) ? 0 : *Map<ForestSize_t, EColumnType::kIndex>(index - 1, &fElemDummy);
-      auto idxEnd = *Map<ForestSize_t, EColumnType::kIndex>(index, &fElemDummy);
+      ClusterSize_t dummy;
+      RColumnElement<ClusterSize_t, EColumnType::kIndex> fElemDummy(&dummy);
+      auto idxStart = (index == 0) ? 0 : *Map<ClusterSize_t, EColumnType::kIndex>(index - 1, &fElemDummy);
+      auto idxEnd = *Map<ClusterSize_t, EColumnType::kIndex>(index, &fElemDummy);
       auto selfOffset = fCurrentPage.GetClusterInfo().GetSelfOffset();
       auto pointeeOffset = fCurrentPage.GetClusterInfo().GetPointeeOffset();
       if (index == selfOffset) {
diff --git a/tree/forest/v7/inc/ROOT/RColumnElement.hxx b/tree/forest/v7/inc/ROOT/RColumnElement.hxx
index 95b5060844812030ddfa2cf0e94df132b48dc902..448aaceae472d0d3a293ace63db8fface97a3957 100644
--- a/tree/forest/v7/inc/ROOT/RColumnElement.hxx
+++ b/tree/forest/v7/inc/ROOT/RColumnElement.hxx
@@ -144,12 +144,12 @@ public:
 
 template <>
 class ROOT::Experimental::Detail::RColumnElement<
-   ROOT::Experimental::ForestSize_t, ROOT::Experimental::EColumnType::kIndex>
+   ROOT::Experimental::ClusterSize_t, ROOT::Experimental::EColumnType::kIndex>
    : public ROOT::Experimental::Detail::RColumnElementBase {
 public:
    static constexpr bool kIsMappable = true;
-   static constexpr size_t kSize = sizeof(ROOT::Experimental::ForestSize_t);
-   explicit RColumnElement(ROOT::Experimental::ForestSize_t* value) : RColumnElementBase(value, kSize, kIsMappable) {}
+   static constexpr size_t kSize = sizeof(ROOT::Experimental::ClusterSize_t);
+   explicit RColumnElement(ROOT::Experimental::ClusterSize_t* value) : RColumnElementBase(value, kSize, kIsMappable) {}
 };
 
 template <>
diff --git a/tree/forest/v7/inc/ROOT/RColumnModel.hxx b/tree/forest/v7/inc/ROOT/RColumnModel.hxx
index b432f2aa2f1c8371aca3a818e3ad636af1d2d599..f4692d59ec0faaf7d54cf1d8ce46b9d779dd8118 100644
--- a/tree/forest/v7/inc/ROOT/RColumnModel.hxx
+++ b/tree/forest/v7/inc/ROOT/RColumnModel.hxx
@@ -56,7 +56,7 @@ enum class EColumnType {
  * Lookup table for the element size in bytes for column types. The array has to correspond to EColumnTypes.
  */
 constexpr std::size_t kColumnElementSizes[] =
-  {0 /* kUnknown */, 8 /* kIndex */, 1 /* kByte */, 8 /* kReal64 */, 4 /* kReal32 */, 2 /* kReal16 */,
+  {0 /* kUnknown */, 4 /* kIndex */, 1 /* kByte */, 8 /* kReal64 */, 4 /* kReal32 */, 2 /* kReal16 */,
    1 /* kReal8 */, 8 /* kInt64 */, 4 /* kInt32 */, 2 /* kInt16 */};
 
 // clang-format off
diff --git a/tree/forest/v7/inc/ROOT/RField.hxx b/tree/forest/v7/inc/ROOT/RField.hxx
index e7b94b7d421aa3352101201c1243c2d558f7d43a..ce82520b563927c2de96d50ec052194f7e664014 100644
--- a/tree/forest/v7/inc/ROOT/RField.hxx
+++ b/tree/forest/v7/inc/ROOT/RField.hxx
@@ -253,7 +253,7 @@ public:
 class RFieldVector : public Detail::RFieldBase {
 private:
    size_t fItemSize;
-   ForestSize_t fNWritten;
+   ClusterSize_t fNWritten;
 
 protected:
    void DoAppend(const Detail::RFieldValueBase& value) final;
@@ -273,6 +273,7 @@ public:
    void DestroyValue(const Detail::RFieldValueBase& value, bool dtorOnly = false) final;
    Detail::RFieldValueBase CaptureValue(void *where) override;
    size_t GetValueSize() const override;
+   void CommitCluster() final;
 };
 
 
@@ -312,14 +313,14 @@ public:
 
    using Detail::RFieldBase::GenerateValue;
    ROOT::Experimental::Detail::RFieldValueBase GenerateValue(void* where) final {
-      return ROOT::Experimental::RFieldValue<ForestSize_t>(
-         Detail::RColumnElement<ForestSize_t, EColumnType::kIndex>(static_cast<ForestSize_t*>(where)),
-         this, static_cast<ForestSize_t*>(where));
+      return ROOT::Experimental::RFieldValue<ClusterSize_t>(
+         Detail::RColumnElement<ClusterSize_t, EColumnType::kIndex>(static_cast<ClusterSize_t*>(where)),
+         this, static_cast<ClusterSize_t*>(where));
    }
    Detail::RFieldValueBase CaptureValue(void* where) final {
-      return ROOT::Experimental::RFieldValue<ForestSize_t>(true,
-         Detail::RColumnElement<ForestSize_t, EColumnType::kIndex>(static_cast<ForestSize_t*>(where)),
-         this, static_cast<ForestSize_t*>(where));
+      return ROOT::Experimental::RFieldValue<ClusterSize_t>(true,
+         Detail::RColumnElement<ClusterSize_t, EColumnType::kIndex>(static_cast<ClusterSize_t*>(where)),
+         this, static_cast<ClusterSize_t*>(where));
    }
    size_t GetValueSize() const final { return 0; }
 };
@@ -329,9 +330,9 @@ public:
 
 
 template <>
-class ROOT::Experimental::RField<ROOT::Experimental::ForestSize_t> : public ROOT::Experimental::Detail::RFieldBase {
+class ROOT::Experimental::RField<ROOT::Experimental::ClusterSize_t> : public ROOT::Experimental::Detail::RFieldBase {
 public:
-   static std::string MyTypeName() { return "ROOT::Experimental::ForestSize_t"; }
+   static std::string MyTypeName() { return "ROOT::Experimental::ClusterSize_t"; }
    explicit RField(std::string_view name) : Detail::RFieldBase(name, MyTypeName(), true /* isSimple */) {}
    RField(RField&& other) = default;
    RField& operator =(RField&& other) = default;
@@ -341,29 +342,34 @@ public:
    void DoGenerateColumns() final;
    unsigned int GetNColumns() const final { return 1; }
 
-   ForestSize_t* Map(ForestSize_t index) {
-      static_assert(Detail::RColumnElement<ForestSize_t, EColumnType::kIndex>::kIsMappable,
-                    "(ForestSize_t, EColumnType::kIndex) is not identical on this platform");
-      return fPrincipalColumn->Map<ForestSize_t, EColumnType::kIndex>(index, nullptr);
+   ClusterSize_t* Map(ForestSize_t index) {
+      static_assert(Detail::RColumnElement<ClusterSize_t, EColumnType::kIndex>::kIsMappable,
+                    "(ClusterSize_t, EColumnType::kIndex) is not identical on this platform");
+      return fPrincipalColumn->Map<ClusterSize_t, EColumnType::kIndex>(index, nullptr);
    }
 
    using Detail::RFieldBase::GenerateValue;
    template <typename... ArgsT>
    ROOT::Experimental::Detail::RFieldValueBase GenerateValue(void* where, ArgsT&&... args)
    {
-      ROOT::Experimental::RFieldValue<ForestSize_t> v(
-         Detail::RColumnElement<ForestSize_t, EColumnType::kIndex>(static_cast<ForestSize_t*>(where)),
-         this, static_cast<ForestSize_t*>(where), std::forward<ArgsT>(args)...);
+      ROOT::Experimental::RFieldValue<ClusterSize_t> v(
+         Detail::RColumnElement<ClusterSize_t, EColumnType::kIndex>(static_cast<ClusterSize_t*>(where)),
+         this, static_cast<ClusterSize_t*>(where), std::forward<ArgsT>(args)...);
       return v;
    }
    ROOT::Experimental::Detail::RFieldValueBase GenerateValue(void* where) final { return GenerateValue(where, 0); }
    Detail::RFieldValueBase CaptureValue(void *where) final {
-      ROOT::Experimental::RFieldValue<ForestSize_t> v(true,
-         Detail::RColumnElement<ForestSize_t, EColumnType::kIndex>(static_cast<ForestSize_t*>(where)),
-         this, static_cast<ForestSize_t*>(where));
+      ROOT::Experimental::RFieldValue<ClusterSize_t> v(true,
+         Detail::RColumnElement<ClusterSize_t, EColumnType::kIndex>(static_cast<ClusterSize_t*>(where)),
+         this, static_cast<ClusterSize_t*>(where));
       return v;
    }
-   size_t GetValueSize() const final { return sizeof(ForestSize_t); }
+   size_t GetValueSize() const final { return sizeof(ClusterSize_t); }
+
+   /// Special help for offset fields
+   void GetCollectionInfo(ForestSize_t index, ForestSize_t* idxStart, ClusterSize_t* size) {
+      fPrincipalColumn->GetCollectionInfo(index, idxStart, size);
+   }
 };
 
 
@@ -489,8 +495,8 @@ public:
 template <>
 class ROOT::Experimental::RField<std::string> : public ROOT::Experimental::Detail::RFieldBase {
 private:
-   ForestSize_t fIndex;
-   Detail::RColumnElement<ForestSize_t, EColumnType::kIndex> fElemIndex;
+   ClusterSize_t fIndex;
+   Detail::RColumnElement<ClusterSize_t, EColumnType::kIndex> fElemIndex;
 
    void DoAppend(const ROOT::Experimental::Detail::RFieldValueBase& value) final;
    void DoRead(ROOT::Experimental::ForestSize_t index, ROOT::Experimental::Detail::RFieldValueBase* value) final;
diff --git a/tree/forest/v7/inc/ROOT/RForestView.hxx b/tree/forest/v7/inc/ROOT/RForestView.hxx
index c969e0740151c8f075794a2f5f51823f97166719..0b43f388d31fdc7365a9b1136f9e7a70746b843a 100644
--- a/tree/forest/v7/inc/ROOT/RForestView.hxx
+++ b/tree/forest/v7/inc/ROOT/RForestView.hxx
@@ -141,7 +141,7 @@ public:
 \brief A tree view for a collection, that can itself generate new tree views for its nested fields.
 */
 // clang-format on
-class RForestViewCollection : public RForestView<ForestSize_t> {
+class RForestViewCollection : public RForestView<ClusterSize_t> {
     friend class RInputForest;
 
 private:
@@ -149,7 +149,7 @@ private:
    Detail::RPageSource* fSource;
 
    RForestViewCollection(std::string_view fieldName, Detail::RPageSource* source)
-      : RForestView<ForestSize_t>(fieldName, source)
+      : RForestView<ClusterSize_t>(fieldName, source)
       , fCollectionName(fieldName)
       , fSource(source)
    {}
@@ -168,8 +168,10 @@ public:
    ~RForestViewCollection() = default;
 
    RForestViewRange GetViewRange(ForestSize_t index) {
-      ForestSize_t start = (index == 0) ? 0 : *fField.Map(index - 1);
-      return RForestViewRange(start, *fField.Map(index));
+      ClusterSize_t size;
+      ForestSize_t idxStart;
+      fField.GetCollectionInfo(index, &idxStart, &size);
+      return RForestViewRange(idxStart, idxStart + size);
    }
    template <typename T>
    RForestView<T> GetView(std::string_view fieldName) { return RForestView<T>(GetSubName(fieldName), fSource); }
@@ -177,9 +179,11 @@ public:
       return RForestViewCollection(GetSubName(fieldName), fSource);
    }
 
-   ForestSize_t operator()(ForestSize_t index) {
-      ForestSize_t offsetPrev = (index == 0) ? 0 : *fField.Map(index - 1);
-      return *fField.Map(index) - offsetPrev;
+   ClusterSize_t operator()(ForestSize_t index) {
+      ClusterSize_t size;
+      ForestSize_t idxStart;
+      fField.GetCollectionInfo(index, &idxStart, &size);
+      return size;
    }
 };
 
diff --git a/tree/forest/v7/src/RField.cxx b/tree/forest/v7/src/RField.cxx
index e889c5f609a83668ae9854736bea197aae030ffd..bc489140cb252ae3c3da3627cdd3d67370fdd6ee 100644
--- a/tree/forest/v7/src/RField.cxx
+++ b/tree/forest/v7/src/RField.cxx
@@ -50,7 +50,7 @@ ROOT::Experimental::Detail::RFieldBase::Create(const std::string &fieldName, con
    if (normalizedType == "string") normalizedType = "std::string";
    if (normalizedType.substr(0, 7) == "vector<") normalizedType = "std::" + normalizedType;
 
-   if (normalizedType == "ROOT::Experimental::ForestSize_t") return new RField<ForestSize_t>(fieldName);
+   if (normalizedType == "ROOT::Experimental::ClusterSize_t") return new RField<ClusterSize_t>(fieldName);
    if (normalizedType == "std::uint32_t") return new RField<std::uint32_t>(fieldName);
    if (normalizedType == "float") return new RField<float>(fieldName);
    if (normalizedType == "double") return new RField<double>(fieldName);
@@ -61,7 +61,7 @@ ROOT::Experimental::Detail::RFieldBase::Create(const std::string &fieldName, con
       return new RFieldVector(fieldName, std::unique_ptr<Detail::RFieldBase>(itemField));
    }
    // TODO: create an RFieldCollection?
-   if (normalizedType == ":Collection:") return new RField<ForestSize_t>(fieldName);
+   if (normalizedType == ":Collection:") return new RField<ClusterSize_t>(fieldName);
    auto cl = TClass::GetClass(normalizedType.c_str());
    if (cl != nullptr) {
       return new RFieldClass(fieldName, normalizedType);
@@ -205,7 +205,7 @@ ROOT::Experimental::RForestEntry* ROOT::Experimental::RFieldRoot::GenerateEntry(
 //------------------------------------------------------------------------------
 
 
-void ROOT::Experimental::RField<ROOT::Experimental::ForestSize_t>::DoGenerateColumns()
+void ROOT::Experimental::RField<ROOT::Experimental::ClusterSize_t>::DoGenerateColumns()
 {
    RColumnModel model(GetName(), EColumnType::kIndex, true /* isSorted*/);
    fColumns.emplace_back(std::make_unique<Detail::RColumn>(model));
@@ -389,7 +389,7 @@ void ROOT::Experimental::RFieldVector::DoAppend(const Detail::RFieldValueBase& v
       auto itemValue = fSubFields[0]->CaptureValue(typedValue->data() + (i * fItemSize));
       fSubFields[0]->Append(itemValue);
    }
-   Detail::RColumnElement<ForestSize_t, EColumnType::kIndex> elemIndex(&fNWritten);
+   Detail::RColumnElement<ClusterSize_t, EColumnType::kIndex> elemIndex(&fNWritten);
    fNWritten += count;
    fColumns[0]->Append(elemIndex);
 }
@@ -397,12 +397,9 @@ void ROOT::Experimental::RFieldVector::DoAppend(const Detail::RFieldValueBase& v
 void ROOT::Experimental::RFieldVector::DoRead(ForestSize_t index, Detail::RFieldValueBase* value) {
    auto typedValue = reinterpret_cast<RFieldValue<std::vector<char>>*>(value)->Get();
 
-   ForestSize_t dummy;
-   Detail::RColumnElement<ForestSize_t, EColumnType::kIndex> elemIndex(&dummy);
-   auto idxStart = (index == 0) ? 0
-      : *fColumns[0]->template Map<ForestSize_t, EColumnType::kIndex>(index - 1, &elemIndex);
-   auto idxEnd = *fColumns[0]->template Map<ForestSize_t, EColumnType::kIndex>(index, &elemIndex);
-   auto nItems = idxEnd - idxStart;
+   ClusterSize_t nItems;
+   ForestSize_t idxStart;
+   fPrincipalColumn->GetCollectionInfo(index, &idxStart, &nItems);
 
    typedValue->resize(nItems * fItemSize);
    for (unsigned i = 0; i < nItems; ++i) {
@@ -453,6 +450,11 @@ size_t ROOT::Experimental::RFieldVector::GetValueSize() const
    return sizeof(std::vector<char>);
 }
 
+void ROOT::Experimental::RFieldVector::CommitCluster()
+{
+   fNWritten = 0;
+}
+
 
 //------------------------------------------------------------------------------
 
diff --git a/tree/forest/v7/test/forest.cxx b/tree/forest/v7/test/forest.cxx
index f28e9ac8576a370397b86961fb382496d098ba9c..2f03cdf37accc6a7fd3deab47a1931c2c3d39950 100644
--- a/tree/forest/v7/test/forest.cxx
+++ b/tree/forest/v7/test/forest.cxx
@@ -202,7 +202,6 @@ TEST(RForest, Clusters)
 
 TEST(RForest, View)
 {
-   // TODO(jblomer): test with multiple clusters
    auto model = RForestModel::Create();
    auto fieldPt = model->MakeField<float>("pt", 42.0);
    auto fieldTag = model->MakeField<std::string>("tag", "xyz");
@@ -213,6 +212,9 @@ TEST(RForest, View)
    {
       ROutputForest forest(std::move(model), std::make_unique<RPageSinkRoot>("f", "test.root"));
       forest.Fill();
+      forest.CommitCluster();
+      fieldJets->clear();
+      forest.Fill();
    }
 
    RInputForest forest(std::make_unique<RPageSourceRoot>("f", "test.root"));
@@ -222,17 +224,21 @@ TEST(RForest, View)
       EXPECT_EQ(42.0, viewPt(i));
       n++;
    }
-   EXPECT_EQ(1, n);
+   EXPECT_EQ(2, n);
 
    auto viewJets = forest.GetView<std::vector<float>>("jets");
    n = 0;
    for (auto i : forest.GetViewRange()) {
-      EXPECT_EQ(2U, viewJets(i).size());
-      EXPECT_EQ(1.0, viewJets(i)[0]);
-      EXPECT_EQ(2.0, viewJets(i)[1]);
+      if (i == 0) {
+         EXPECT_EQ(2U, viewJets(i).size());
+         EXPECT_EQ(1.0, viewJets(i)[0]);
+         EXPECT_EQ(2.0, viewJets(i)[1]);
+      } else {
+         EXPECT_EQ(0U, viewJets(i).size());
+      }
       n++;
    }
-   EXPECT_EQ(1, n);
+   EXPECT_EQ(2, n);
 }
 
 TEST(RForest, Capture) {
@@ -270,6 +276,8 @@ TEST(RForest, Composable)
             fldTracks->Fill();
          }
          *fldPt = float(i);
+         //if (i == 2)
+         //   forest->CommitCluster();
          forest->Fill();
       }
    }