How can I perform tensor contractions without first storing an unnecessarily large tensor?

I'm performing a calculation which requires me to start with a collection of tensors and contract out their indices according to a pattern that I've written down. Right now, if I have a pair of two index tensors $A_{ij}$ and $B_{nm}$, and I want to contract out the second index of $A$ with the first index of $B$, I would write

TensorContract[TensorProduct[A,B], {2,3}]


This works acceptably whenever the tensors are of reasonable size, but unfortunately, my arrays quickly become quite large. In particular, on the last step of my calculation, I have a pair of 28-index objects (each with two values, so in total $2^{28}$ elements each) that I need to tensor product together. I then want to contract out 16 pairs of indices, so that I'm left with a 24-index object. Unfortunately, my computer's memory can't seem to handle the step where I need to create the intermediate 56-index object. Hence my question: is there a smarter way to perform tensor contractions that doesn't require the creation of an intermediate object with a higher rank? It seems wasteful to build the intermediate object, but I don't know of any (straightforward) workarounds. Is there a simple way to address this problem?

I should also mention that these arrays are quite sparse, and I have made all of my tensors into sparse arrays. In particular, for my 28-index object with $2^{28}$ entries, only $2^{13}$ of them are nonzero. But even with sparcity, this is killing my computer. So any advice is very welcome!