You are right about the interpretation of the betas when there is a single categorical variable with $k$ levels.  If there were multiple categorical variables (and there were no interaction term), the intercept ($\hat\beta_0$) is the mean of the group that constitute the reference level for *both* (all) categorical variables.  Using your example scenario, consider the case where there is no interaction, then the betas are:  

 - $\hat\beta_0$: the mean of white males
 - $\hat\beta_{\rm Female}$: the *difference* between the mean of females and the mean of white males
 - $\hat\beta_{\rm Black}$: the *difference* between the mean of black males and the mean of white males

We can also think of this in terms of how to calculate the various group means:  
\begin{align}
 &\bar x_{\rm White\ Males}&   &= \hat\beta_0  \\
 &\bar x_{\rm White\ Females}& &= \hat\beta_0 + \hat\beta_{\rm Female}  \\
 &\bar x_{\rm Black\ Males}&   &= \hat\beta_0 + \hat\beta_{\rm Black}  \\
 &\bar x_{\rm Black\ Females}& &= \hat\beta_0 + \hat\beta_{\rm Female} + \hat\beta_{\rm Black}
\end{align}

If you had an interaction term, it would be added at the end of the equation for black females.  (The interpretation of such an interaction term is quite convoluted, but I walk through it here: [Interpretation of interaction term](http://stats.stackexchange.com/a/122251/7290).)  

------------------------------------
*Update*:  To clarify my points, let's consider a canned example.  

    d = data.frame(Sex  =factor(rep(c("Male","Female"),times=2), levels=c("Male","Female")),
                   Race =factor(rep(c("White","Black"),each=2),  levels=c("White","Black")),
                   y    =c(1, 3, 5, 7))
    d
    #      Sex  Race y
    # 1   Male White 1
    # 2 Female White 3
    # 3   Male Black 5
    # 4 Female Black 7

![enter image description here][1]

The means of `y` for these categorical variables are:  

    aggregate(y~Sex,  d, mean)
    #      Sex y
    # 1   Male 3
    # 2 Female 5
    aggregate(y~Race, d, mean)
    #    Race y
    # 1 White 2
    # 2 Black 6

We can compare these means to the coefficients from a fitted model:  

    summary(lm(y~Sex+Race, d))
    # ...
    # Coefficients:
    #             Estimate Std. Error  t value Pr(>|t|)    
    # (Intercept)        1   3.85e-16 2.60e+15  2.4e-16 ***
    # SexFemale          2   4.44e-16 4.50e+15  < 2e-16 ***
    # RaceBlack          4   4.44e-16 9.01e+15  < 2e-16 ***
    # ...
    # Warning message:
    #   In summary.lm(lm(y ~ Sex + Race, d)) :
    #   essentially perfect fit: summary may be unreliable

The thing to recognize about this situation is that, without an interaction term, we are assuming parallel lines.  


  [1]: https://i.sstatic.net/cEHiC.png