This plan is generating 96 million reads, anything you can point it that could be improve?
Most cardinality estimates are ballpark, which is lucky given that the plan is driven to a large extent by a recursive common table expression. These are hard to estimate for in general. There are a couple of plan areas that are concerning, which I'll come to in a moment.
The query seems quite large and complex, so I would start by breaking it down a bit. A natural place to start would be to run the recursive common table expression separately and store the results in a temporary table. The CTE is referenced twice, and fully computed twice in the query plan.
Materializing it would remove this duplication of effort, and result in much better cardinality and distribution information. You would also be free to create any potentially helpful indexes on the temporary table, giving the optimizer even better information to work with.
There are a number of scans and seeks in this plan that produce a large number of rows. I would look at those to see if more selective indexing could be provided. It might also be that the optimizer is choosing a strategy based on a smaller expected number of rows, so you might see the plan shape change once the CTE has been materialized. Nevertheless, you will want to avoid operators that produce many millions of rows where it can be avoided.
There appear to be a number of simple aggregations on large numbers of rows in the plan. Consider pre-calculating these using indexed views. If you are not using Enterprise Edition, you will need to replace the aggregations explicitly with view references using the NOEXPAND hint.
The query uses parallelism, but is limited to DOP 4. The query appears to be mostly CPU-bound, so you could think about making more processors available for this task.
The memory grant for the query is excessive. Around 1.2GB is reserved, though I cannot be sure from the anonymized plan on your version of SQL Server how much of that is used at runtime. At least some of your tuning effort should be directed to reducing that memory grant. If you are able to use indexed views instead of big hash aggregations, that will help.
The index seeks on Table8.Index4 and Table6.Index5 are executed 10,724,610 times each. The estimates are good in this area of the plan, so you need to look carefully at the query logic and indexes to see if this can be improved. Both index seeks have residual predicates which you may be able to incorporate into the seek by changing your indexing, adding computed columns, or some other action.
More generally, the plan is probably too large to expect great results from the optimizer, and it is likely reasonably difficult to read and maintain. It is easy to visually break the query into sections that produce reasonable row counts. I would definitely break this query up into simpler sections using temporary tables. This would go well beyond the recursive CTEs, to be clear about it.
Probably something to be done in the top branch on the HASH branching to table6.index5. 2920 rows come in and go out yet that read has 1.7 million rows included to produce the same row counts before and after.